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 ≤ 10,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
好惨啊……有一个加1的没写结果最裸的树链剖分调了一整天
线段树维护最大值和最小值,对于一条链上权值取反的操作只要mx=-mn,mn=-mx即可
#include<cstdio> #include<iostream> #include<cstring> #define LL long long #define inf 1000000000 #define N 10010 using namespace std; int bin[15]={1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384}; inline LL read() { LL x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } struct segtree{int l,r,mx,mn,tag;}tree[4*N]; struct edge{int to,next,v;}e[2*N]; int T,n,cnt,tt,mx; char ch[10]; int head[N]; int fa[N][15],son[N],depth[N],v[N]; bool mrk[N]; int place[N],pplace[N],belong[N]; int query[N]; inline void revswap(int &a,int &b){int t=a;a=-b;b=-t;} inline void ins(int u,int v,int w) { e[++cnt].to=v; e[cnt].v=w; e[cnt].next=head[u]; head[u]=cnt; } inline void insert(int u,int v,int w) { ins(u,v,w); ins(v,u,w); } inline void dfs(int x,int dep) { if (mrk[x])return;mrk[x]=1; depth[x]=dep;son[x]=1; for (int i=1;i<15;i++) if (bin[i]<=depth[x]) fa[x][i]=fa[fa[x][i-1]][i-1]; else break; for (int i=head[x];i;i=e[i].next) if (!mrk[e[i].to]) { fa[e[i].to][0]=x; dfs(e[i].to,dep+1); v[e[i].to]=e[i].v; son[x]+=son[e[i].to]; query[(i+1)>>1]=e[i].to; } } inline void dfs2(int x,int chain) { place[x]=++tt;pplace[tt]=x; belong[x]=chain; int res=0,mx=-inf; for (int i=head[x];i;i=e[i].next) if (fa[x][0]!=e[i].to) { if (son[e[i].to]>mx) { mx=son[e[i].to]; res=e[i].to; } } if (!res)return; dfs2(res,chain); for (int i=head[x];i;i=e[i].next) if (fa[x][0]!=e[i].to&&res!=e[i].to) dfs2(e[i].to,e[i].to); } inline int LCA(int a,int b) { if (depth[a]<depth[b])swap(a,b); int res=depth[a]-depth[b]; for (int i=0;i<15;i++) if (res & bin[i]) a=fa[a][i]; for (int i=14;i>=0;i--) if (fa[a][i]!=fa[b][i]) { a=fa[a][i]; b=fa[b][i]; } if (a==b)return a; return fa[a][0]; } inline void pushdown(int k) { tree[k].tag=0; tree[k<<1].tag^=1;tree[k<<1|1].tag^=1; revswap(tree[k<<1].mx,tree[k<<1].mn); revswap(tree[k<<1|1].mx,tree[k<<1|1].mn); } inline void update(int k) { tree[k].mx=max(tree[k<<1].mx,tree[k<<1|1].mx); tree[k].mn=min(tree[k<<1].mn,tree[k<<1|1].mn); } inline void buildtree(int now,int l,int r) { tree[now].l=l;tree[now].r=r; if (l==r) { tree[now].mx=tree[now].mn=v[pplace[l]]; return; } int mid=(l+r)>>1; buildtree(now<<1,l,mid); buildtree(now<<1|1,mid+1,r); update(now); } inline void change_in_tree(int now,int x,int y) { int l=tree[now].l,r=tree[now].r; if (l!=r&&tree[now].tag)pushdown(now); if (l==r) { tree[now].mx=tree[now].mn=y; return; } int mid=(l+r)>>1; if (x<=mid)change_in_tree(now<<1,x,y); else change_in_tree(now<<1|1,x,y); update(now); } inline void negate_in_tree(int now,int x,int y) { int l=tree[now].l,r=tree[now].r; if (l!=r&&tree[now].tag)pushdown(now); if (l==x&&r==y) { revswap(tree[now].mx,tree[now].mn); tree[now].tag=1; return; } int mid=(l+r)>>1; if (y<=mid)negate_in_tree(now<<1,x,y); else if (x>mid)negate_in_tree(now<<1|1,x,y); else { negate_in_tree(now<<1,x,mid); negate_in_tree(now<<1|1,mid+1,y); } update(now); } inline void ask_in_tree(int now,int x,int y) { int l=tree[now].l,r=tree[now].r; if (l!=r&&tree[now].tag)pushdown(now); if (l==x&&r==y) { mx=max(mx,tree[now].mx); return; } int mid=(l+r)>>1; if (y<=mid)ask_in_tree(now<<1,x,y); else if (x>mid)ask_in_tree(now<<1|1,x,y); else { ask_in_tree(now<<1,x,mid); ask_in_tree(now<<1|1,mid+1,y); } } inline void reverse(int from,int to) { if (from==to)return; int l,r; while (belong[from]!=belong[to]) { l=place[belong[from]];r=place[from]; negate_in_tree(1,l,r); from=fa[belong[from]][0]; } if (place[to]+1<=place[from]) negate_in_tree(1,place[to]+1,place[from]); } inline int ask(int from,int to) { int l,r;mx=-inf; if (from==to)return mx; while (belong[from]!=belong[to]) { l=place[belong[from]];r=place[from]; ask_in_tree(1,l,r); from=fa[belong[from]][0]; } if (place[to]+1<=place[from]) ask_in_tree(1,place[to]+1,place[from]); return mx; } inline void work() { memset(tree,0,sizeof(tree)); memset(head,0,sizeof(head)); memset(e,0,sizeof(e)); memset(mrk,0,sizeof(mrk)); memset(query,0,sizeof(query)); memset(place,0,sizeof(place)); memset(pplace,0,sizeof(pplace)); memset(belong,0,sizeof(belong)); memset(fa,0,sizeof(fa)); memset(son,0,sizeof(son)); memset(depth,0,sizeof(depth)); memset(v,0,sizeof(v)); tt=cnt=0; n=read(); for (int i=1;i<n;i++) { int x=read(),y=read(),z=read(); insert(x,y,z); } dfs(1,0); dfs2(1,1); buildtree(1,1,n); while (scanf("%s",ch+1)&&ch[1]!='D') { int a=read(),b=read(); if (ch[1]=='C')change_in_tree(1,place[query[a]],b); if (ch[1]=='N') { int c=LCA(a,b); reverse(a,c); reverse(b,c); } if (ch[1]=='Q') { int c=LCA(a,b); printf("%d\n",max( ask(a,c),ask(b,c) )); } } } int main() { T=read(); while (T--)work(); }