[POJ3237]Tree
题目描述 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:
|
||||||
输入描述 Input Description |
||||||
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 Description |
||||||
For each “ |
||||||
样例输入 Sample Input |
||||||
1 3 1 2 1 2 3 2 QUERY 1 2 CHANGE 1 3 QUERY 1 2 DONE |
||||||
样例输出 Sample Output |
||||||
1 3 |
||||||
数据范围及提示 Data Size & Hint |
||||||
之前的一些废话:是时候准备会考了。。
题解:树链剖分+线段树,其中tag[o]表示pushdown的时候儿子需不需要再次反转。
代码:
#include<iostream> #include<cmath> #include<algorithm> #include<cstring> #include<queue> #include<cstdio> using namespace std; typedef long long LL; #define mem(a,b) memset(a,b,sizeof(a)) typedef pair<int,int> PII; inline int read() { int x=0,f=1;char c=getchar(); while(!isdigit(c)){if(c=='-')f=-1;c=getchar();} while(isdigit(c)){x=x*10+c-'0';c=getchar();} return x*f; } const int maxn=10010,oo=2147483647; int T,n,m,a,b,c,ce,es,first[maxn],deep[maxn],size[maxn],ms[maxn],fa[maxn],bl[maxn],id[maxn],Eid[maxn]; int A[maxn],Max[maxn<<2],Min[maxn<<2],tag[maxn<<2]; char s[5]; struct Edge { int u,v,w,next; Edge() {} Edge(int _1,int _2,int _3,int _4):u(_1),v(_2),w(_3),next(_4) {} }e[maxn<<1]; void addEdge(int a,int b,int c) { e[++ce]=Edge(a,b,c,first[a]);first[a]=ce; e[++ce]=Edge(b,a,c,first[b]);first[b]=ce; } void rev(int o){int a=Max[o];Max[o]=-Min[o];Min[o]=-a;} void pushdown(int l,int r,int o) { int mid=(l+r)>>1,lo=o<<1,ro=lo|1; if(l==r || !tag[o])return; tag[o]=0;tag[lo]^=1;tag[ro]^=1; rev(lo);rev(ro); } void pushup(int l,int r,int o) { int mid=(l+r)>>1,lo=o<<1,ro=lo|1; Max[o]=max(Max[lo],Max[ro]); Min[o]=min(Min[lo],Min[ro]); } void build(int l,int r,int o) { int mid=(l+r)>>1,lo=o<<1,ro=lo|1; if(l==r) { Max[o]=Min[o]=A[l]; return; } build(l,mid,lo);build(mid+1,r,ro); pushup(l,r,o); } void update(int l,int r,int o,int a,int b) { int mid=(l+r)>>1,lo=o<<1,ro=lo|1; if(l==r) { tag[o]=0;Min[o]=Max[o]=b; return; } pushdown(l,r,o); if(a>mid)update(mid+1,r,ro,a,b); else update(l,mid,lo,a,b); pushup(l,r,o); } void Negate(int l,int r,int o,int a,int b) { int mid=(l+r)>>1,lo=o<<1,ro=lo|1; if(l==a && r==b) { tag[o]^=1;rev(o); return; } pushdown(l,r,o); if(b<=mid)Negate(l,mid,lo,a,b); else if(a>mid)Negate(mid+1,r,ro,a,b); else Negate(l,mid,lo,a,mid),Negate(mid+1,r,ro,mid+1,b); pushup(l,r,o); } int query(int l,int r,int o,int a,int b) { int mid=(l+r)>>1,lo=o<<1,ro=lo|1; if(l==a && r==b)return Max[o]; pushdown(l,r,o); if(b<=mid)return query(l,mid,lo,a,b); else if(a>mid)return query(mid+1,r,ro,a,b); else return max(query(l,mid,lo,a,mid),query(mid+1,r,ro,mid+1,b)); } void dfs(int now,int pa) { size[now]=1; for(int i=first[now];i!=-1;i=e[i].next) if(e[i].v!=pa) { fa[e[i].v]=now;deep[e[i].v]=deep[now]+1; dfs(e[i].v,now); size[now]+=size[e[i].v]; if(size[e[i].v]>size[ms[now]])ms[now]=e[i].v; } } void divide(int now,int chain) { id[now]=++es;bl[now]=chain; if(ms[now])divide(ms[now],chain); for(int i=first[now];i!=-1;i=e[i].next) if(e[i].v!=fa[now]) { if(e[i].v!=ms[now])divide(e[i].v,e[i].v); Eid[(i+2)>>1]=e[i].v;A[id[e[i].v]]=e[i].w; } } int lca(int a,int b) { while(bl[a]!=bl[b]) { if(deep[bl[a]]<deep[bl[b]])swap(a,b); a=fa[bl[a]]; } return deep[a]<deep[b] ? a : b; } void change(int a,int b) { while(bl[a]!=bl[b]) { if(deep[bl[a]]<deep[bl[b]])swap(a,b); Negate(1,n,1,id[bl[a]],id[a]); a=fa[bl[a]]; } if(id[b]+1<=id[a])Negate(1,n,1,id[b]+1,id[a]); } int ask(int a,int b) { int ans=-oo; while(bl[a]!=bl[b]) { if(deep[bl[a]]<deep[bl[b]])swap(a,b); ans=max(ans,query(1,n,1,id[bl[a]],id[a])); a=fa[bl[a]]; } if(id[b]+1<=id[a])ans=max(ans,query(1,n,1,id[b]+1,id[a])); return ans; } int main() { T=read(); while(T--) { mem(first,-1);mem(e,0);mem(fa,0);mem(deep,0);mem(size,0);mem(ms,0);mem(bl,0);mem(id,0);mem(Eid,0); mem(A,0);mem(Max,0);mem(Min,0);mem(tag,0);ce=-1;es=0; n=read(); for(int i=1;i<n;i++)a=read(),b=read(),c=read(),addEdge(a,b,c); dfs(1,-1);divide(1,1);build(1,n,1); while(1) { scanf("%s",s); if(s[0]=='D')break; a=read();b=read(); if(s[0]=='C')update(1,n,1,id[Eid[a]],b); if(s[0]=='N') { int c=lca(a,b); change(a,c);change(b,c); } if(s[0]=='Q') { int c=lca(a,b); printf("%d\n",max(ask(a,c),ask(b,c))); } } } return 0; }
总结:线段树的细节一定要想明白再写,最好先把线形的写好,并且对拍无误再上树。