洛谷 P2590 [ZJOI2008]树的统计
题目描述
一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。
我们将以下面的形式来要求你对这棵树完成一些操作:
I. CHANGE u t : 把结点u的权值改为t
II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值
III. QSUM u v: 询问从点u到点v的路径上的节点的权值和
注意:从点u到点v的路径上的节点包括u和v本身
输入输出格式
输入格式:
输入文件的第一行为一个整数n,表示节点的个数。
接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有一条边相连。
接下来一行n个整数,第i个整数wi表示节点i的权值。
接下来1行,为一个整数q,表示操作的总数。
接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。
输出格式:
对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。
输入输出样例
输入样例#1:
4 1 2 2 3 4 1 4 2 1 3 12 QMAX 3 4 QMAX 3 3 QMAX 3 2 QMAX 2 3 QSUM 3 4 QSUM 2 1 CHANGE 1 5 QMAX 3 4 CHANGE 3 6 QMAX 3 4 QMAX 2 4 QSUM 3 4
输出样例#1:
4 1 2 2 10 6 5 6 5 16
说明
对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。
模版树剖
#include <ctype.h> #include <cstdio> #define N 50000 void read(int &x) { x=0; bool f=0; char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') f=1;ch=getchar();} while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} x=f?(~x)+1:x; } struct Edge { int next,to; }edge[N<<1]; struct Tree { int l,r,dis,Max; Tree *left,*right; Tree() { left=right=NULL; dis=Max=0; } }*root; int dfn[N],Q,dis[N],head[N],cnt,n,top[N],fa[N],dep[N],tim,size[N],belong[N]; int max(int a,int b) {return a>b?a:b;} void add(int u,int v) { ++cnt; edge[cnt].next=head[u]; edge[cnt].to=v; head[u]=cnt; } void dfs1(int x) { size[x]=1; dep[x]=dep[fa[x]]+1; for(int i=head[x];i;i=edge[i].next) { int v=edge[i].to; if(fa[x]!=v) { fa[v]=x; dfs1(v); size[x]+=size[v]; } } } void dfs2(int x) { belong[x]=++tim; dfn[tim]=x; int t=0; if(!top[x]) top[x]=x; for(int i=head[x];i;i=edge[i].next) { int v=edge[i].to; if(fa[x]!=v&&size[t]<size[v]) t=v; } if(t) top[t]=top[x],dfs2(t); for(int i=head[x];i;i=edge[i].next) { int v=edge[i].to; if(fa[x]!=v&&v!=t) dfs2(v); } } void build(Tree *&k,int l,int r) { k=new Tree; k->l=l;k->r=r; if(l==r) { k->dis=k->Max=dis[dfn[l]]; return; } int mid=(l+r)>>1; build(k->left,l,mid); build(k->right,mid+1,r); k->dis=k->left->dis+k->right->dis; k->Max=max(k->left->Max,k->right->Max); } void Tree_change(Tree *&k,int t,int z) { if(k->l==k->r) { k->dis=k->Max=z; return; } int mid=(k->l+k->r)>>1; if(mid>=t) Tree_change(k->left,t,z); else Tree_change(k->right,t,z); k->dis=k->left->dis+k->right->dis; k->Max=max(k->left->Max,k->right->Max); } void swap(int &x,int &y) { int tmp=y; y=x; x=tmp; } int Tree_Query_Max(Tree *&k,int l,int r) { if(k->l==l&&k->r==r) return k->Max; int mid=(k->l+k->r)>>1; if(l>mid) return Tree_Query_Max(k->right,l,r); else if(r<=mid) return Tree_Query_Max(k->left,l,r); else return max(Tree_Query_Max(k->left,l,mid),Tree_Query_Max(k->right,mid+1,r)); } int Chain_Query_Max(int x,int y) { int ans=-0x7fffffff; for(;top[x]!=top[y];x=fa[top[x]]) { if(dep[top[x]]<dep[top[y]]) swap(x,y); ans=max(ans,Tree_Query_Max(root,belong[top[x]],belong[x])); } if(belong[x]>belong[y]) swap(x,y); ans=max(ans,Tree_Query_Max(root,belong[x],belong[y])); return ans; } int Tree_Query_Sum(Tree *&k,int l,int r) { if(k->l==l&&k->r==r) return k->dis; int mid=(k->l+k->r)>>1; if(l>mid) return Tree_Query_Sum(k->right,l,r); else if(r<=mid) return Tree_Query_Sum(k->left,l,r); else return Tree_Query_Sum(k->left,l,mid)+Tree_Query_Sum(k->right,mid+1,r); } int Chain_Query_Sum(int x,int y) { int ans=0; for(;top[x]!=top[y];x=fa[top[x]]) { if(dep[top[x]]<dep[top[y]]) swap(x,y); ans+=Tree_Query_Sum(root,belong[top[x]],belong[x]); } if(belong[x]>belong[y]) swap(x,y); ans+=Tree_Query_Sum(root,belong[x],belong[y]); return ans; } int main() { read(n); for(int a,b,i=1;i<n;i++) { read(a); read(b); add(a,b); add(b,a); } for(int i=1;i<=n;i++) read(dis[i]); dfs1(1); dfs2(1); read(Q); root=new Tree; build(root,1,n); char str[11]; for(int x,y;Q--;) { scanf("%s",str+1); if(str[1]=='C') { read(x); read(y); Tree_change(root,belong[x],y); } else if(str[2]=='M') { read(x); read(y); printf("%d\n",Chain_Query_Max(x,y)); } else { read(x); read(y); printf("%d\n",Chain_Query_Sum(x,y)); } } return 0; }
我们都在命运之湖上荡舟划桨,波浪起伏着而我们无法逃脱孤航。但是假使我们迷失了方向,波浪将指引我们穿越另一天的曙光。