[ZJOI2008]树的统计

来源:互联网 发布:单片机组成 编辑:程序博客网 时间:2024/06/15 22:46
[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之间。

题解:
树链剖分,维护max和sum就可以了。

代码:
#include<cstdio>#include<iostream>#include<cstring>#include<cstdlib>using namespace std;const int max_n = 300001;const int inf = 1e9+7;struct tree_l{int l,r;int max,num,tot;}tree[max_n*4];char c[11];int point[max_n],nxt[max_n],v[max_n],val[max_n];int fa[max_n],top[max_n],size[max_n],rank_n[max_n],deep[max_n];int n,m,a,b,q,tot,tans,mans,root;inline void init(){memset(point,-1,sizeof(point));memset(nxt,-1,sizeof(nxt));tot=-1; root=1;}inline void update(int now){tree[now].tot=tree[now<<1].tot+tree[(now<<1)+1].tot;tree[now].max=max(tree[now<<1].max,tree[(now<<1)+1].max);}inline void addedge(int x,int y){++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;++tot; nxt[tot]=point[y]; point[y]=tot; v[tot]=x; }inline void change(int now,int l,int r,int val){int lr=tree[now].l,rr=tree[now].r;if(l<=lr && rr<=r){tree[now].tot=val;tree[now].num=val;tree[now].max=val;return;}int mid=(lr+rr)>>1;if(l<=mid) change(now<<1,l,r,val);if(r>mid) change((now<<1)+1,l,r,val);update(now);}inline void build(int now,int l,int r){tree[now].l=l; tree[now].r=r;if(l==r){tree[now].max=tree[now].num=tree[now].tot=-inf;return;}int mid=(l+r)>>1;    build(now<<1,l,mid);    build((now<<1)+1,mid+1,r);}inline void dfs1(int now,int f){fa[now]=f;deep[now]=deep[f]+1;size[now]=1;for(int i=point[now]; i!=-1; i=nxt[i])  if(v[i]!=f)  {  dfs1(v[i],now);  size[now]+=size[v[i]];  }}inline void dfs2(int now,int tip){top[now]=tip;rank_n[now]=++tot;change(1,tot,tot,val[now]);int mson=0;if(now!=root && nxt[point[now]]==-1) return;for(int i=point[now]; i!=-1; i=nxt[i])  if(size[v[i]]<size[now] && size[v[i]]>size[mson]) mson=v[i];dfs2(mson,tip);for(int i=point[now]; i!=-1; i=nxt[i])  if(size[v[i]]<size[now] && v[i]!=mson)dfs2(v[i],v[i]);}inline void query(int now,int l,int r){int lr=tree[now].l,rr=tree[now].r;if(l<=lr && rr<=r){mans=max(tree[now].max,mans);tans+=tree[now].tot;return;}int mid=(lr+rr)>>1;if(l<=mid) query(now<<1,l,r);if(r>mid) query((now<<1)+1,l,r);}inline void squery(int x,int y){while(top[x]!=top[y]){if(deep[top[x]]<deep[top[y]]) swap(x,y);query(1,rank_n[top[x]],rank_n[x]);x=fa[top[x]]; }if(rank_n[x]>rank_n[y]) swap(x,y);query(1,rank_n[x],rank_n[y]);}int main(){//freopen("bzoj_1036.in","r",stdin);//freopen("bzoj_1036.out","w",stdout);scanf("%d",&n);init();for(int i=1; i<=n-1; ++i){scanf("%d%d",&a,&b);addedge(a,b);}for(int i=1; i<=n; ++i)  scanf("%d",&val[i]);  tot=0;build(1,1,n);dfs1(root,1);dfs2(root,root);scanf("%d",&q);for(int i=1; i<=q; ++i){scanf("%s%d%d",c,&a,&b);tans=0; mans=-inf;if(c[3]=='N') change(1,rank_n[a],rank_n[a],b);if(c[3]=='X') squery(a,b),printf("%d\n",mans);if(c[3]=='M') squery(a,b),printf("%d\n",tans);}return 0;}




原创粉丝点击