【DSY-2117】Moore Manor

2117: Moore Manor

Once upon a time, there was a place called Moore Manor. There are n houses in Moore Manor, numbered 1 to n. There are tunnel connections between houses. Since the builders were lazy, they only built n−1 tunnels, each of length 1. For the house numbered i(i>1), there is a link numbered ⌊ i 2 ⌋ \left\lfloor\frac{i}{2}\right\rfloor2i The tunnel of the house. Tunnels are bidirectional. For each house, we know that the house has ci servings of food for up to ci Rams.

In this huge n houses live m rams, numbered from 1 to m. For the ith Ram, it starts out in house number pi. All Rams start out sleeping. The next morning, Ram with a number less than or equal to k woke up, while the other m−k Rams remained asleep. This k ram will choose a house with food and climb over it. They want to know what is the minimum sum of their crawl distances on the premise that the k rams have food to eat.

Remember the minimum value of the sum of k only ram crawl distances as f(k), you need to output f(1),f(2),f(3),…,f(m).

ideas

tree dp + network stream

Simulate network flow with tree dp.

1

Obviously, the title given is a complete binary tree.

Preprocessing, maintaining the number and distance of the nearest house with food in the current subtree (including itself) of each house.

Then enter a pi p_i each timepi, Immediately iii only Ram's position, find the current optimal solution (retain the previous answer).

That is to say, after calculating the answer when there is only one ram, in this state (the first ram ate the nearest food), calculate the distance from the second ram to the food.

2

According to this approach, obviously, there is no guarantee that the answer is optimal.

So to simulate network flow.

picture

As shown in the figure, according to the method described in 1, the second situation in the figure cannot be obtained from the first situation in the figure.

Because, after the first ram eats the food from house 4, the second ram will go to 5, the distance is 2, to eat the food.

Therefore, let flowi flow_iflowimeans after iiThe number of tree edges between point i and its parent.

If a stream flows from point iison of i or itself, leading to pointiiThe father of i , that is, the tree edge between this point and its father has passed from this point, thenflowi ← 1 flow_i \gets1flowi1 ; otherwise, subtract 1.

Let the initial cost of each tree edge be 1,

  • If you want to go from the son by the tree to the father at this time:

    • f l o w i > = 0 flow_i>=0 flowi>=0 , the cost is 1;

    • f l o w i < 0 flow_i<0 flowi<0 , i.e. there is more flow from father to son by comparison, then the cost is -1.

  • If you want to go from the father by the tree to the son at this time:

    • f l o w i < = 0 flow_i<=0 flowi<=0 , the cost is 1;

    • f l o w i > 0 flow_i>0 flowi>0 , i.e. there is more flow from father to son by comparison, then the cost is -1.

The purpose of this is to offset.

With the above flowi < 0 flow_i < 0 from son to fatherflowi<The case of 0 is an example, becauseflowi < 0 flow_i<0flowi<0 , so it means that there are more flows from the father to the son at the edge of the tree, then the cost is -1, which can be offset with the previous path from the father to the son with a cost of 1.

3

Every time you calculate the distance, walk up from the starting point of the ram, and every time you look at the current node, whether the distance from it to the nearest house with food in its subtree can refresh the minimum value, and finally take the minimum value. value.

After the calculation, update the traffic of each node and maintain the nearest food point of each node.

code

Be sure to remember to give dis dis firstd is assigned a maximum value.

#include<bits/stdc++.h>
using namespace std;

#define maxn 200005
#define rep(i, a, b) for(int i = a; i <= b; ++i)

int n, m, c[maxn];
int ans, dis[maxn], pos[maxn], flw[maxn];
int s, t, tt, nw, cst;

inline int Flow(int x, int fx)
{
    
    
	if(fx == 1)//up
		return flw[x] < 0 ? -1 : 1;
	else//down
		return flw[x] > 0 ? -1 : 1;
}

inline void updt(int x)
{
    
    
	int l = x << 1, r = x << 1 | 1;
	dis[x] = 2e9, pos[x] = 0;
	if(c[x])
		dis[x] = 0, pos[x] = x;
	if(dis[x] > dis[l] + Flow(l, 0))
		dis[x] = dis[l] + Flow(l, 0), pos[x] = pos[l];
	if(dis[x] > dis[r] + Flow(r, 0))
		dis[x] = dis[r] + Flow(r, 0), pos[x] = pos[r];
}

int main()
{
    
    
	memset(dis, 127 / 3, sizeof dis);
	scanf("%d %d", &n, &m);
	rep(i, 1, n) scanf("%d", &c[i]);
	for(int i = n; i >= 1; --i) updt(i);
	while(m--)
	{
    
    
		cst = 2e9, nw = t = 0;
		scanf("%d", &s);
		for(int i = s; i; i >>= 1)
		{
    
    
			if(cst > dis[i] + nw)
				cst = dis[i] + nw, t = i;
			nw += Flow(i, 1);
		}
		tt = pos[t], ans += cst;
		for(int i = s; i > t; i >>= 1) flw[i] += 1;
		for(int i = tt; i > t; i >>= 1) flw[i] -= 1;
		c[tt] -= 1;
		for(int i = tt; i > t; i >>= 1) updt(i);
		for(int i = s; i; i >>= 1) updt(i);
		printf("%d ", ans);
	}
	return 0; 
}

—— E n d End End——

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=324030205&siteId=291194637