Poj3237-Tree(树链剖分)
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 bwith 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
题意:给出一棵树,有3种操作,一是修改一条边的边权,二是将两个点之间所有边的边权置为相反数,三是查询两个点之间最大边权。
解析:树链剖分,用线段树维护区间最大值,因为有置相反数这一个操作,我在线段树里加三个变量minv(最小值),maxv(最大值),d(懒惰标记,要进行置相反数操作时乘上-1),
区间置了相反数则最大值变最小值,最小值变最大值。
代码
#include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<vector> using namespace std; #define tu nod[u] #define tv nod[v] #define e tree[id] #define lson tree[id*2] #define rson tree[id*2+1] const int maxn=10005; const int INF=1e9+7; int N,pid; vector<int> G[maxn]; struct edge { int u,v,c; edge(int u=0,int v=0,int c=0):u(u),v(v),c(c){} }E[maxn]; struct node { int top,fa,deep;//top所属树链的顶点,fa父节点,deep深度 int s,p,son; //s以它为子树的大小,p新编号,son重链所指向的点 }nod[maxn]; void dfs(int u,int fa,int deep) { tu.fa=fa,tu.deep=deep,tu.s=1; //保存父节点,深度,大小为1 int Size=G[u].size(); for(int i=0;i<Size;i++) { int v=G[u][i]; if(v==fa) continue; //父亲不管 dfs(v,u,deep+1); tu.s+=tv.s; //加上子树大小 if(tu.son==-1||tv.s>nod[tu.son].s) tu.son=v; //找重链节点 } } void Div(int u,int top) { tu.top=top; //重链顶点 tu.p=++pid; //重新编号 if(tu.son!=-1) Div(tu.son,top); //有重链继续往下找 else return; int Size=G[u].size(); for(int i=0;i<Size;i++) { int v=G[u][i]; if(v==tu.fa||v==tu.son) continue; Div(v,v); //新的链 } } struct Tree { int le,ri,minv,maxv,d; void Set(){ swap(minv,maxv); minv=-minv; maxv=-maxv; d*=-1; } //交换,并置相反数 }tree[4*maxn]; void pushup(int id) { e.minv=min(lson.minv,rson.minv); //更新最大值最小值 e.maxv=max(lson.maxv,rson.maxv); } void pushdown(int id){ if(e.d==-1) lson.Set(), rson.Set(), e.d=1; } //延迟更新 void Build_tree(int id,int le,int ri) //建树 { e.le=le,e.ri=ri,e.d=1; e.minv=INF,e.maxv=-INF; if(le==ri) return; int mid=(le+ri)/2; Build_tree(id*2,le,mid); Build_tree(id*2+1,mid+1,ri); } void Update1(int id,int k,int v) //单点更新 { int le=e.le,ri=e.ri; if(le==ri){ e.minv=e.maxv=v; return; } pushdown(id); int mid=(le+ri)/2; if(k<=mid) Update1(id*2,k,v); else Update1(id*2+1,k,v); pushup(id); } void Update2(int id,int x,int y) //成段更新 { int le=e.le,ri=e.ri; if(x<=le&&ri<=y){ e.Set(); return; } pushdown(id); int mid=(le+ri)/2; if(x<=mid) Update2(id*2,x,y); if(y>mid) Update2(id*2+1,x,y); pushup(id); } int Query(int id,int x,int y) //查询 { int le=e.le,ri=e.ri; if(x<=le&&ri<=y) return e.maxv; pushdown(id); int mid=(le+ri)/2; int ret=-INF; if(x<=mid) ret=max(ret,Query(id*2,x,y)); if(y>mid) ret=max(ret,Query(id*2+1,x,y)); return ret; } int GetAns(int u,int v) //查询路径最大边权 { int f1=tu.top,f2=tv.top; int ret=-INF; while(f1!=f2) //不在同一条链上 { if(nod[f1].deep<nod[f2].deep){ swap(f1,f2); swap(u,v); } ret=max(ret,Query(1,nod[f1].p,tu.p)); //查询这条链上的 u=nod[f1].fa; f1=tu.top; //跳到父节点去 } if(u==v) return ret; if(tu.deep>tv.deep) swap(u,v); ret=max(ret,Query(1,nod[tu.son].p,tv.p)); return ret; } void Negate(int u,int v) //区间置相反数,跟上面同理,查询变成了更新 { int f1=tu.top,f2=tv.top; while(f1!=f2) { if(nod[f1].deep<nod[f2].deep){ swap(f1,f2); swap(u,v); } Update2(1,nod[f1].p,tu.p); u=nod[f1].fa; f1=tu.top; } if(u==v) return; if(tu.deep>tv.deep) swap(u,v); Update2(1,nod[tu.son].p,tv.p); } int main() { int T; scanf("%d",&T); while(T--) { scanf("%d",&N); for(int i=0;i<=N;i++) G[i].clear(),nod[i].son=-1; pid=0; for(int i=1;i<N;i++) { int u,v,c; scanf("%d%d%d",&u,&v,&c); E[i]=edge(u,v,c); G[u].push_back(v); G[v].push_back(u); } dfs(1,0,0); Div(1,1); Build_tree(1,1,pid); for(int i=1;i<N;i++) { edge& t=E[i]; int& u=t.u; int& v=t.v; if(tu.deep>tv.deep) swap(u,v); Update1(1,tv.p,t.c); //偏向v点 } char op[10]; while(scanf("%s",op)!=EOF) { if(op[0]=='D') break; int a,b; scanf("%d%d",&a,&b); if(op[0]=='C') Update1(1,nod[E[a].v].p,b); else if(op[0]=='Q') printf("%d\n",GetAns(a,b)); else Negate(a,b); } } return 0; }