洛谷 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<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define MAXN 1000000 using namespace std; int n,q,sz,tot; int w[MAXN],id[MAXN]; int dad[MAXN],deep[MAXN],size[MAXN],top[MAXN]; int to[MAXN],head[MAXN],net[MAXN]; struct nond{ int l,r,dis,sum; }tree[MAXN]; void add(int u,int v){ to[++tot]=v;net[tot]=head[u];head[u]=tot; to[++tot]=u;net[tot]=head[v];head[v]=tot; } void up(int now){ tree[now].sum=tree[now*2].sum+tree[now*2+1].sum; tree[now].dis=max(tree[now*2].dis,tree[now*2+1].dis); } void build(int now,int l,int r){ tree[now].l=l;tree[now].r=r; if(tree[now].l==tree[now].r) return ; int mid=(tree[now].l+tree[now].r)/2; build(now*2,l,mid); build(now*2+1,mid+1,r); } void change(int now,int x,int k){ if(tree[now].l==tree[now].r){ tree[now].dis=k; tree[now].sum=k; return ; } int mid=(tree[now].l+tree[now].r)/2; if(x<=mid) change(now*2,x,k); else if(x>mid) change(now*2+1,x,k); up(now); } int query(int now,int l,int r,int z){ if(tree[now].l==l&&tree[now].r==r){ if(z==1) return tree[now].dis; else if(z==0) return tree[now].sum; } int mid=(tree[now].l+tree[now].r)/2; if(r<=mid) return query(now*2,l,r,z); else if(l>mid) return query(now*2+1,l,r,z); else{ if(z==1) return max(query(now*2,l,mid,z),query(now*2+1,mid+1,r,z)); else if(z==0) return query(now*2,l,mid,z)+query(now*2+1,mid+1,r,z); } } void dfs(int x){ size[x]=1; deep[x]=deep[dad[x]]+1; for(int i=head[x];i;i=net[i]) if(dad[x]!=to[i]){ dad[to[i]]=x; dfs(to[i]); size[x]+=size[to[i]]; } } void dfs1(int x){ int t=0; id[x]=++sz; if(!top[x]) top[x]=x; change(1,sz,w[x]); for(int i=head[x];i;i=net[i]) if(dad[x]!=to[i]&&size[t]<size[to[i]]) t=to[i]; if(t){ top[t]=top[x]; dfs1(t); } for(int i=head[x];i;i=net[i]) if(dad[x]!=to[i]&&t!=to[i]) dfs1(to[i]); } int squery(int x,int y,int z){ int ans; if(z==1) ans=-0x7f7f7f7f; else ans=0; while(top[x]!=top[y]){ if(deep[top[x]]<deep[top[y]]) swap(x,y); if(z==1) ans=max(ans,query(1,id[top[x]],id[x],1)); else ans+=query(1,id[top[x]],id[x],0); x=dad[top[x]]; } if(id[x]>id[y]) swap(x,y); if(z==1) ans=max(ans,query(1,id[x],id[y],1)); else ans+=query(1,id[x],id[y],0); return ans; } int main(){ scanf("%d",&n); for(int i=1;i<n;i++){ int u,v; scanf("%d%d",&u,&v); add(u,v); } for(int i=1;i<=n;i++) scanf("%d",&w[i]); build(1,1,n); dfs(1); dfs1(1); scanf("%d",&q); for(int i=1;i<=q;i++){ char a[10];int u,v; scanf("%s%d%d",a,&u,&v); if(a[1]=='H') change(1,id[u],v); else if(a[1]=='M') printf("%d\n",squery(u,v,1)); else printf("%d\n",squery(u,v,0)); } }
细雨斜风作晓寒。淡烟疏柳媚晴滩。入淮清洛渐漫漫。
雪沫乳花浮午盏,蓼茸蒿笋试春盘。人间有味是清欢。