标签:
You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, 3...N-1.
We will ask you to perfrom some instructions of the following form:
The first line of input contains an integer t, the number of test cases (t <= 20). t test cases follow.
For each test case:
There is one blank line between successive tests.
For each "QUERY" operation, write one integer representing its result.
Input: 1 3 1 2 1 2 3 2 QUERY 1 2 CHANGE 1 3 QUERY 1 2 DONE Output: 1 3
题意:给出一棵树,有两种操作,一种是修改边权,另一种是查询两个点之间最大边权。
解析:裸的树链剖分,用线段树维护区间最大值。
代码
#include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<cmath> #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; int N,pid; vector<int> G[maxn]; struct node { int top,fa,deep;//top所属树链的顶点,fa父节点,deep深度 int s,p,fp,son; //s以它为子树的大小,p新编号,fp相对p反向的,这题里面没什么用,son重链所指向的点 }nod[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]; void init() { pid=0; for(int i=0;i<maxn;i++) G[i].clear(),nod[i].son=-1; //初始化 } 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; //重新编号 nod[tu.p].fp=u; 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,v; }tree[4*maxn]; void pushup(int id){ e.v=max(lson.v,rson.v); } void Build_tree(int id,int le,int ri) { e.le=le,e.ri=ri,e.v=0; if(le==ri) return; int mid=(le+ri)/2; Build_tree(id*2,le,mid); Build_tree(id*2+1,mid+1,ri); } void Update(int id,int k,int v) { int le=e.le,ri=e.ri; if(le==ri){ e.v=v; return; } int mid=(le+ri)/2; if(k<=mid) Update(id*2,k,v); else Update(id*2+1,k,v); pushup(id); } int Query(int id,int x,int y) { int le=e.le,ri=e.ri; if(x<=le&&ri<=y) return e.v; int mid=(le+ri)/2; int ret=0; 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 Find(int u,int v) { int f1=tu.top,f2=tv.top; int ret=0; while(f1!=f2) //不在同一条链上 { if(nod[f1].deep<nod[f2].deep) //总是让u是深度大的点 { 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; } int main() { int T; scanf("%d",&T); while(T--) { scanf("%d",&N); init(); 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); Update(1,tv.p,t.c); //修改边权 } char op[15]; while(scanf("%s",op)!=EOF) { int u,v; if(op[0]==‘D‘) break; scanf("%d%d",&u,&v); if(op[0]==‘Q‘) printf("%d\n",Find(u,v)); //查询 else Update(1,nod[E[u].v].p,v); //更新 } } return 0; }
标签:
原文地址:http://www.cnblogs.com/wust-ouyangli/p/5722343.html