POJ3237 Tree(树剖+线段树+lazy标记)
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
题意:
对于一棵树,有几种操作:
Q :x y 。问x到y之间的路径的最大边权值为多少。
C :x y。把第x条边的权值改为y。
N:x y。把x到y之间的边权值取反。
D。结束。
思路:
和前面一道树剖题的查询是一样的,所以同样需要树剖+线段树,对于C操作,同样是线段树单点更新即可。但是需要区间权值取反,得用lazy标记一下。记录最大和最小值,方便在取反后还能得到最大值。
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #include<cmath> #define min(a,b) (a<b?a:b) #define max(a,b) (a>b?a:b) #define swap(a,b) (a^=b,b^=a,a^=b) using namespace std; const int maxn=200010; int Laxt[maxn],Next[maxn],To[maxn],e[maxn][3],cnt; int n,q; char opt[10]; struct TreeCut { int dpt[maxn],top[maxn],son[maxn],fa[maxn],sz[maxn],tot; int tid[maxn],Rank[maxn],tim; int Max[maxn<<2],Min[maxn<<2],Lazy[maxn<<2]; void init() { cnt=1; tim=0; memset(Laxt,0,sizeof(Laxt)); memset(Max,0,sizeof(Max)); memset(Min,0,sizeof(Min)); memset(Lazy,0,sizeof(Lazy)); } void add_edge(int u,int v) { Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v; } void dfs1(int u,int pre) { fa[u]=pre;dpt[u]=dpt[pre]+1;sz[u]=1;son[u]=0; for(int i=Laxt[u];i;i=Next[i]){ int v=To[i]; if(v==pre) continue; dfs1(v,u);sz[u]+=sz[v]; if(!son[u]||sz[v]>sz[son[u]]) son[u]=v; } } void pushdown(int Now) { swap(Max[Now<<1],Min[Now<<1]),Max[Now<<1]=-Max[Now<<1],Min[Now<<1]=-Min[Now<<1]; swap(Max[Now<<1|1],Min[Now<<1|1]),Max[Now<<1|1]=-Max[Now<<1|1],Min[Now<<1|1]=-Min[Now<<1|1]; Lazy[Now<<1]^=1;Lazy[Now<<1|1]^=1;Lazy[Now]=0; } void pushup(int Now) { Max[Now]=max(Max[Now<<1],Max[Now<<1|1]); Min[Now]=min(Min[Now<<1],Min[Now<<1|1]); } void dfs2(int u,int Top) { top[u]=Top; tid[u]=tim++;Rank[tid[u]]=u; if(!son[u]) return ; dfs2(son[u],Top); for(int i=Laxt[u];i;i=Next[i]) if(To[i]!=fa[u]&&To[i]!=son[u]) dfs2(To[i],To[i]); } void update(int Now,int L,int R,int pos,int val) { if(L==R){ Max[Now]=Min[Now]=val; return; } if(Lazy[Now]&1) pushdown(Now); int Mid=(L+R)>>1; if(Mid>=pos) update(Now<<1,L,Mid,pos,val); else update(Now<<1|1,Mid+1,R,pos,val); pushup(Now); } int getmax(int Now,int L,int R,int l,int r) { if(L>=l&&R<=r) return Max[Now]; if(Lazy[Now]&1) pushdown(Now); int Mid=(L+R)>>1,ans=-0x7fffffff; if(r<=Mid) ans=getmax(Now<<1,L,Mid,l,r); else if(l>Mid) ans=getmax(Now<<1|1,Mid+1,R,l,r); else ans=max(getmax(Now<<1,L,Mid,l,Mid),getmax(Now<<1|1,Mid+1,R,Mid+1,r)); pushup(Now); return ans; } void addsign(int Now,int L,int R,int l,int r) { if(L>=l&&R<=r) { Lazy[Now]^=1;swap(Max[Now],Min[Now]); Max[Now]=-Max[Now];Min[Now]=-Min[Now]; return ; } if(Lazy[Now]&1) pushdown(Now); int Mid=(L+R)>>1; if(l<=Mid) addsign(Now<<1,L,Mid,l,r); if(r>Mid) addsign(Now<<1|1,Mid+1,R,l,r); pushup(Now); } void Make_Tree() { scanf("%d",&n); for(int i=1;i<n;i++){ scanf("%d%d%d",&e[i][0],&e[i][1],&e[i][2]); add_edge(e[i][0],e[i][1]);add_edge(e[i][1],e[i][0]); } dfs1(1,0); dfs2(1,1); for(int i=1;i<n;i++){ if(dpt[e[i][1]]<dpt[e[i][0]]) swap(e[i][1],e[i][0]); update(1,1,n-1,tid[e[i][1]],e[i][2]); } } int query(int u,int v) { int f1=top[u],f2=top[v],ans=-0x7fffffff; while(f1!=f2){ if(dpt[f1]<dpt[f2]) swap(f1,f2),swap(u,v); ans=max(ans,getmax(1,1,n-1,tid[f1],tid[u])); u=fa[f1]; f1=top[u]; } if(u!=v){ if(dpt[u]>dpt[v]) swap(u,v); ans=max(ans,getmax(1,1,n-1,tid[son[u]],tid[v])); } printf("%d\n",ans); } int Add_lazy(int u,int v) { int f1=top[u],f2=top[v]; while(f1!=f2){ if(dpt[f1]<dpt[f2]) swap(f1,f2),swap(u,v); addsign(1,1,n-1,tid[f1],tid[u]); u=fa[f1]; f1=top[u]; } if(u!=v){ if(dpt[u]>dpt[v]) swap(u,v); addsign(1,1,n-1,tid[son[u]],tid[v]); } } void Query() { while(~scanf("%s",opt)) { if(opt[0]=='D') return; int x,y; scanf("%d%d",&x,&y); if(opt[0]=='Q') query(x,y); else if(opt[0]=='N') Add_lazy(x,y); else update(1,1,n-1,tid[e[x][1]],y); } } }Tc; int main() { int T; scanf("%d",&T); while(T--) { Tc.init(); Tc.Make_Tree(); Tc.Query(); } return 0; }