Time Limit: 5000MS | Memory Limit: 131072K | |
Total Submissions: 9233 | Accepted: 2431 |
Description
You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edges are numbered 1 through N − 1. Each edge is associated with a weight. Then you are to execute a series of instructions on the tree. The instructions can be one of the following forms:
CHANGE i v |
Change the weight of the ith edge to v |
NEGATE a b |
Negate the weight of every edge on the path from a to b |
QUERY a b |
Find the maximum weight of edges on the path from a to b |
Input
The input contains multiple test cases. The first line of input contains an integer t (t ≤ 20), the number of test cases. Then follow the test cases.
Each test case is preceded by an empty line. The first nonempty line of its contains N (N ≤ 100,000). The next N − 1 lines each contains three integers a, b and c, describing an edge connecting nodes a and b with weight c. The edges are numbered in the order they appear in the input. Below them are the instructions, each sticking to the specification above. A lines with the word “DONE
” ends the test case.
Output
For each “QUERY
” instruction, output the result on a separate line.
Sample Input
1 3 1 2 1 2 3 2 QUERY 1 2 CHANGE 1 3 QUERY 1 2 DONE
Sample Output
1 3
Source
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define maxn 1000005 using namespace std; struct TreeNodeType { int l,r,dis,dis_,mid,flag; }; struct TreeNodeType tree[maxn<<2]; struct EdgeType { int v,w,next; }; struct EdgeType edge[maxn<<1]; int u_[maxn],v_[maxn]; int if_z,t,n,cnt,head[maxn],deep[maxn],f[maxn]; int flag[maxn],top[maxn],size[maxn],dis[maxn],dis_[maxn]; char Cget; inline void in(int &now) { now=0,if_z=1,Cget=getchar(); while(Cget>'9'||Cget<'0') { if(Cget=='-') if_z=-1; Cget=getchar(); } while(Cget>='0'&&Cget<='9') { now=now*10+Cget-'0'; Cget=getchar(); } now*=if_z; } inline void edge_add(int u,int v,int w) { edge[++cnt].v=v,edge[cnt].w=w,edge[cnt].next=head[u],head[u]=cnt; edge[++cnt].v=u,edge[cnt].w=w,edge[cnt].next=head[v],head[v]=cnt; } void search_1(int now,int fa) { int pos=cnt++; deep[now]=deep[fa]+1,f[now]=fa; for(int i=head[now];i;i=edge[i].next) { if(edge[i].v==fa) continue; dis_[edge[i].v]=edge[i].w; search_1(edge[i].v,now); } size[now]=cnt-pos; } void search_2(int now,int chain) { int pos=0; top[now]=chain; flag[now]=++cnt; dis[flag[now]]=dis_[now]; for(int i=head[now];i;i=edge[i].next) { if(edge[i].v==f[now]) continue; if(size[edge[i].v]>size[pos]) pos=edge[i].v; } if(pos==0) return ; search_2(pos,chain); for(int i=head[now];i;i=edge[i].next) { if(edge[i].v==f[now]||edge[i].v==pos) continue; search_2(edge[i].v,edge[i].v); } } inline void tree_up(int now) { tree[now].dis=max(tree[now<<1].dis,tree[now<<1|1].dis); tree[now].dis_=min(tree[now<<1].dis_,tree[now<<1|1].dis_); } inline void tree_down(int now) { if(tree[now].l==tree[now].r) return ; tree[now<<1].dis*=-1,tree[now<<1|1].dis*=-1; tree[now<<1].dis_*=-1,tree[now<<1|1].dis_*=-1; tree[now<<1].flag*=-1,tree[now<<1|1].flag*=-1; swap(tree[now<<1].dis_,tree[now<<1].dis); swap(tree[now<<1|1].dis_,tree[now<<1|1].dis); tree[now].flag=1;return ; } void tree_build(int now,int l,int r) { tree[now].l=l,tree[now].r=r,tree[now].flag=1; if(l==r) { tree[now].dis=dis[l]; tree[now].dis_=tree[now].dis; return ; } tree[now].mid=(l+r)>>1; tree_build(now<<1,l,tree[now].mid); tree_build(now<<1|1,tree[now].mid+1,r); tree_up(now); } void tree_change(int now,int to,int x) { if(tree[now].l==tree[now].r) { tree[now].dis=x; tree[now].dis_=x; return ; } if(tree[now].flag==-1) tree_down(now); if(to<=tree[now].mid) tree_change(now<<1,to,x); else tree_change(now<<1|1,to,x); tree_up(now); } void tree_negate(int now,int l,int r) { if(tree[now].l==l&&tree[now].r==r) { tree[now].dis*=-1; tree[now].dis_*=-1; swap(tree[now].dis,tree[now].dis_); tree[now].flag*=-1; return ; } if(tree[now].flag==-1) tree_down(now); if(l>tree[now].mid) tree_negate(now<<1|1,l,r); else if(r<=tree[now].mid) tree_negate(now<<1,l,r); else { tree_negate(now<<1,l,tree[now].mid); tree_negate(now<<1|1,tree[now].mid+1,r); } tree_up(now); } int tree_query(int now,int l,int r) { if(tree[now].l==l&&tree[now].r==r) { return tree[now].dis; } if(tree[now].flag==-1) tree_down(now); if(l>tree[now].mid) return tree_query(now<<1|1,l,r); else if(r<=tree[now].mid) return tree_query(now<<1,l,r); else { return max(tree_query(now<<1,l,tree[now].mid),tree_query(now<<1|1,tree[now].mid+1,r)); } } int solve_query(int x,int y) { int pos=-0x7ffffff; while(top[x]!=top[y]) { if(deep[top[x]]<deep[top[y]]) swap(x,y); pos=max(pos,tree_query(1,flag[top[x]],flag[x])); x=f[top[x]]; } if(x==y) return pos; if(deep[x]>deep[y]) swap(x,y); pos=max(pos,tree_query(1,flag[x]+1,flag[y])); return pos; } void solve_negate(int x,int y) { while(top[x]!=top[y]) { if(deep[top[x]]<deep[top[y]]) swap(x,y); tree_negate(1,flag[top[x]],flag[x]); x=f[top[x]]; } if(x==y) return ; if(deep[x]>deep[y]) swap(x,y); tree_negate(1,flag[x]+1,flag[y]); } int main() { in(t); while(t--) { memset(head,0,sizeof(head)); in(n);cnt=0; int u,v,w;char ch[10]; for(int i=1;i<n;i++) { in(u),in(v),in(w); u_[i]=u,v_[i]=v,edge_add(u,v,w); } cnt=0,search_1(1,0); cnt=0,search_2(1,1); tree_build(1,1,n); for(int i=1;i<n;i++) { if(deep[u_[i]]<deep[v_[i]]) swap(u_[i],v_[i]); } while(1) { cin>>ch; if(ch[0]=='D') break; in(u),in(v); if(ch[0]=='N') solve_negate(u,v); if(ch[0]=='C') tree_change(1,flag[u_[u]],v); if(ch[0]=='Q') { cout<<solve_query(u,v); putchar(' '); } } } return 0; }