Guagua's time travel, the third simulation competition, dfs order + line segment tree maintenance minimum

Topic description

       The watermelons live in n parallel space-times numbered 1...n, and 2n−2 time machines connect these parallel space-times together. A time machine has 3 integer parameters u, v, t, which means that it can take t time to travel from space-time u to space-time v. In order to ensure that time and space can travel to each other, and at the same time to facilitate the passage of space-time No. 1 in this world, the watermelons divide these time machines: the first n−1 units. Time machines ensure that space-time No. 1 can directly/indirectly reach any time and space, The last n-1 time machines are responsible for returning directly to the space-time No. 1 from the space-time No. 2...n. q1 watermelons hope to travel from some time and space to some time and space. Obviously, wise watermelons will choose the most time-saving route. However, the time machine is not stable, during which time the time machine's running time changes q2 times. The watermelon king was eaten, and he wants you to tell his people the time required for the current optimal route for the watermelons.

I /O Format
5 7 2
1 3 1
3 2 2
1 4 3
3 5 4
5 1 5
3 1 6
2 1 7
4 1 8
1 1 1
1 1 3
1 3 5
1 5 2
2 1 100
1 1 3
2 8 30
1 4 2

1 2 4

Input format:




8
100
132
10

The three integers n, q1, and q2 in the first line represent the number of parallel space-time, watermelon and time machine changes, respectively.
Next 2n-2 lines, each line of 3 integers u, v, t represents a time machine.
Next q1+q2 lines, each line contains t, x, y integers:
if t=1, it means that there is currently a watermelon that wants to travel from space-time to space-time;
if t=2, it means that the running time of the first time machine becomes .

Output format:

Line q1, for each x,y, output a line representing the time required for the current optimal route.


Input example:


5 7 2
1 3 1
3 2 2
1 4 3
3 5 4
5 1 5
3 1 6
2 1 7
4 1 8
1 1 1
1 1 3
1 3 5
1 5 2
2 1 100
1 1 3
2 8 30
1 4 2

1 2 4


Output sample




8
100
132

10

      Simplifying the meaning of the question, we can know that the first n-1 edges make n points an outgoing tree, that is to say, it can only go from the parent node to the subtree.

      The last n-1 edges indicate that each node has 1 way to the root node.

      So how many ways can x get to y?

       1. y is in the subtree of x, just search down

       2. y is not in the subtree of x, go directly from x to the root, and then go from the root to the y node.

       3. If y is not in the subtree of x, go to the subtree first, then go to the root from that point, and go to the y node from the root (may be better than 2).

      1 can be processed directly, directly subtract the distance from the root to x from the distance from the root to y.

      2 and 3 seem to be very simple, but the time complexity is very high.

      In fact, the problem can be transformed into   the problem of finding the minimum value in the subtree   .

      Then, to make the interval in the subtree continuous, we can use dfs to traverse it, mark it once on the stack, and mark it once on the stack.

      We have obtained a dfs order, and it is natural to use a line segment tree to maintain the minimum value .

      We use the dis array to represent the path length from the root to x, and the to array to represent the distance from x to the root.

      Then we can know that let x be the starting point, y is the end point and is not in the subtree of x, and i is any point of the subtree of x.

      It is necessary to make dis[i]-dis[x]+to[i]+dis[y] minimum.

      Transform the formula to get: dis[i]+to[i] -dis[x]+dis[y] .

     It is easy to find that -dis[x]+dis[y] is constant, so to minimize the original formula, we need to minimize dis[i]+to[i].

     So the line segment tree maintains this dis[i]+to[i] .

     When typing the code, it is found that the dis[i] array cannot be updated in time, so we can directly use the value in the line segment tree minus to[i] to represent it without knowing dis.

      Change sides:

      1. The first n-1 edges are changed, and the distance from the v node and its subtree to the root should be changed (plus the new value - (dis[v]-dis[u]) (the original edge weight) ) (dis Seeking as above)

       2. Change the last n-1 edges, directly change to[u], and update the u value of the line segment tree (plus the new value -to[u])

      Finally, pay attention to the minimum value (l[i]) and the maximum value (r[i]) of the current subtree number when traversing the dfs.

      Obviously the number of the current point is l[i]. This number (for line segment tree maintenance) and the original number (parallel space-time) should not be confused.

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;

int n,m,q;
struct edge{
	int x,y,next;
	long long c;
}s[200010];
struct tree{
	int ls,rs;
	int x,y;
	long long lazy;
	long long mmin;
}tr[400010];
long long to[200010];
long long dis[200010];
int len ​​= 0;
int first[200010];
int z = 0, l [200010], r [200010];
int at[200010];

void ins(int x,int y,long long c){
	len ++;
	s[len].x=x;s[len].y=y;s[len].c=c;s[len].next=first[x];first[x]=len;
}

void bt(int x,int y){
	len ++;
	tr[len].x=x;tr[len].y=y;
	tr [len] .ls = -1; tr [len] .rs = -1;
	tr[len].mmin=1e16;
	tr [len] .lazy = 0;
	if(x==y) {
		tr [len] .mmin = 0;
		return ;
	}
	int mid=(x+y)/2;
	int i = len;
	tr[i].ls=len+1;bt(x,mid);
	tr[i].rs=len+1;bt(mid+1,y);
}

void pushdown(int x){
	int ls=tr[x].ls,rs=tr[x].rs;
	if(tr[ls].ls==-1 && tr[ls].rs==-1) tr[ls].mmin+=tr[x].lazy;
	else tr[ls].lazy+=tr[x].lazy,tr[ls].mmin+=tr[x].lazy;
	if(tr[rs].ls==-1 && tr[rs].rs==-1) tr[rs].mmin+=tr[x].lazy;
	else tr[rs].lazy+=tr[x].lazy,tr[rs].mmin+=tr[x].lazy;
	tr[x].lazy=0;
}

void change(int p,int x,int y,long long t){
	if(tr[p].ls==-1 && tr[p].rs==-1) {
		tr[p].mmin+=t;
		return ;
	}
	if(tr[p].x==x && tr[p].y==y){
		tr[p].lazy+=t;
		tr[p].mmin+=t;
		return ;
	}
	pushdown(p);
	int mid=tr[tr[p].ls].y;
	if(y<=mid) change(tr[p].ls,x,y,t);
	else if(x>mid) change(tr[p].rs,x,y,t);
	else change(tr[p].ls,x,mid,t),change(tr[p].rs,mid+1,y,t);
	tr[p].mmin=min(tr[tr[p].ls].mmin,tr[tr[p].rs].mmin);
}

long long get_min(int p,int x,int y){
	if(tr[p].x==x && tr[p].y==y)
		return tr[p].mmin;
	pushdown(p);
	int mid=tr[tr[p].ls].y;
	if(y<=mid) return get_min(tr[p].ls,x,y);
	else if(x>mid) return get_min(tr[p].rs,x,y);
	else return min(get_min(tr[p].ls,x,mid),get_min(tr[p].rs,mid+1,y));
}

void dfs(int x){
	l[x]=++z;
	for(int i=first[x];i!=0;i=s[i].next){
		int y=s[i].y;
		dis [y] = dis [x]+s [i] .c;
		dfs(y);
	}
	r[x]=z;
}

int main(){
	freopen("b.in","r",stdin);
	freopen("b.out","w",stdout);
	scanf("%d %d %d",&n,&m,&q);
	for(int i=1;i<=n-1;i++){
		int x,y;
		long long c;
		scanf("%d %d %lld",&x,&y,&c);
		ins(x,y,c);
	}
	for(int i=1;i<=n-1;i++){
		int x,y;
		long long c;
		scanf("%d %d %lld",&x,&y,&c);
		to[x]=c;
		op[i]=x;
	}
	dfs(1);
	len = 0;
	bt (1, n);
	for(int i=1;i<=n;i++) change(1,l[i],l[i],dis[i]+to[i]);
	for(int i=1;i<=m+q;i++){
		int t,x,y;
		scanf("%d %d %d",&t,&x,&y);
		if(t==1){
			if(l[x]<=l[y] && l[y]<=r[x]) printf("%lld\n",(get_min(1,l[y],l[y])-to[y])-(get_min(1,l[x],l[x])-to[x]));
			else printf("%lld\n",get_min(1,l[x],r[x])-(get_min(1,l[x],l[x])-to[x])+(get_min(1,l[y],l[y])-to[y]));
		}
		else {
			if(x<=n-1)
				change(1,l[s[x].y],r[s[x].y],y-((get_min(1,l[s[x].y],l[s[x].y])-to[s[x].y])-(get_min(1,l[s[x].x],l[s[x].x])-to[s[x].x])));
			else{
				x-=n-1;
				change (1, l [on [x]], l [on [x]], y-to [on [x]]);
				to [on [x]] = y;
			}
		}
	}
}

      

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325977953&siteId=291194637