codevs 2460 树的统计
题目描述 Description
一棵树上有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本身
输入描述 Input Description
输入文件的第一行为一个整数n,表示节点的个数。
接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有一条边相连。
接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。
接下来1行,为一个整数q,表示操作的总数。
接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。
输出描述 Output Description
对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。
样例输入 Sample Input
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
样例输出 Sample Output
4
1
2
2
10
6
5
6
5
16
数据范围及提示 Data Size & Hint
对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。
分类标签 Tags 点此展开
思路:树链剖分搞一下就好。
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define MAXN 30010 using namespace std; int n,q,sz,tot; int w[MAXN]; int top[MAXN],id[MAXN]; int to[MAXN*2],net[MAXN*2],head[MAXN]; int dad[MAXN],size[MAXN],deep[MAXN]; struct nond{ int l,r,max,sum; }tree[MAXN*4]; 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].max=max(tree[now*2].max,tree[now*2+1].max); } 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); up(now); } void change(int now,int pos,int x){ if(tree[now].l==tree[now].r){ tree[now].max=x;tree[now].sum=x; return ; } int mid=(tree[now].l+tree[now].r)/2; if(pos<=mid) change(now*2,pos,x); else if(pos>mid) change(now*2+1,pos,x); up(now); } int query(int now,int l,int r,int k){ if(tree[now].l==l&&tree[now].r==r){ if(k==1) return tree[now].max; else if(k==2) return tree[now].sum; } int mid=(tree[now].l+tree[now].r)/2; if(r<=mid) return query(now*2,l,r,k); else if(l>mid) return query(now*2+1,l,r,k); else{ if(k==1) return max(query(now*2,l,mid,k),query(now*2+1,mid+1,r,k)); else if(k==2) return query(now*2,l,mid,k)+query(now*2+1,mid+1,r,k); } } void dfs(int now){ size[now]=1; deep[now]=deep[dad[now]]+1; for(int i=head[now];i;i=net[i]) if(dad[now]!=to[i]){ dad[to[i]]=now; dfs(to[i]); size[now]+=size[to[i]]; } } void dfs1(int x){ int t=0;id[x]=++sz; if(!top[x]) top[x]=x; change(1,id[x],w[x]); for(int i=head[x];i;i=net[i]) if(dad[x]!=to[i]&&size[to[i]]>size[t]) 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 pos){ int ans; if(pos==2) ans=0; else if(pos==1) ans=-0x7f7f7f7f; for(;top[x]!=top[y];){ if(deep[top[x]]<deep[top[y]]) swap(x,y); if(pos==2) ans+=query(1,id[top[x]],id[x],pos); else if(pos==1) ans=max(ans,query(1,id[top[x]],id[x],pos)); x=dad[top[x]]; } if(id[x]>id[y]) swap(x,y); if(pos==2) ans+=query(1,id[x],id[y],pos); else if(pos==1) ans=max(ans,query(1,id[x],id[y],pos)); 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 c[5];int u,v; cin>>c;scanf("%d%d",&u,&v); if(c[0]=='C') change(1,id[u],v); else if(c[0]=='Q'&&c[1]=='M') printf("%d\n",squery(u,v,1)); else printf("%d\n",squery(u,v,2)); } }
细雨斜风作晓寒。淡烟疏柳媚晴滩。入淮清洛渐漫漫。
雪沫乳花浮午盏,蓼茸蒿笋试春盘。人间有味是清欢。