BZOJ1036: [ZJOI2008]树的统计Count
2018-01-09 11:44
453 查看
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
输入的第一行为一个整数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
对于每个“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 Constraint
对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。Solution
这是一道非常明显的树剖题树剖就是把一棵树剖分成轻链和重链,放入线段树中处理各种信息,便于处理(查询和修改)树中路径上的值。
将树中的边分为:轻边和重边,定义size(X)为以X为根的子树的节点个数。令V为U的儿子节点中size值最大的节点,那么边(U,V)被称为重边,树中重边之外的边被称为轻边。
性质:轻边(U,V),size(V)<=size(U)/2。
具体方法:
1.dfs一次,处理出每个点的子树大小(size),深度(dep),父亲(fa),重儿子(son)。
2.再dfs一次,因为在数据结构中一条重链是连续的一段,所以要重新编号及处理出每个点在的重链的顶端(top)。
void dfs2(int x,int topp) { w[x]=++totw; top[x]=topp; if (son[x]!=0)dfs2(son[x],top[x]);//沿着重链走,所以top不变 for (int i=last[x];i!=0;i=side[i].next) if (side[i].y!=son[x] && side[i].y!=fa[x]) dfs2(side[i].y,side[i].y);//新的一条链,这个点即顶端。 }
3.当要查询两点间路径上的信息时,
若两点在同一条重链上,就可以直接查询。
若不在同一重链上,把深的点跳到其top的父亲,并计算它到top这段的值。最终两点一定会在一条重链上。
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<cmath> using namespace std; #define N 30030 #define INF 0x7fffffff struct edge { int y,next; }; struct tr { int ma,sum; }; tr tree[N*4]; edge side[N*2]; int size ,last ,fa ,son ,dep ,num ,top ,w ; int n,m,tot,totw; char ch[15]; void add(int x,int y) { ++tot; side[tot].y=y; side[tot].next=last[x]; last[x]=tot; } void init() { scanf("%d",&n); int x,y; memset(last,0,sizeof(last)); for (int i=1;i<=n-1;i++) { scanf("%d%d",&x,&y); add(x,y); add(y,x); } for (int i=1;i<=n;i++) scanf("%d",&num[i]); } void dfs1(int x) { size[x]=1; son[x]=0; for (int i=last[x];i!=0;i=side[i].next) if (side[i].y!=fa[x]) { int j=side[i].y; fa[j]=x; dep[j]=dep[x]+1; dfs1(j); size[x]+=size[j]; if (size[j]>size[son[x]]) son[x]=j; } } void dfs2(int x,int topp) { w[x]=++totw; top[x]=topp; if (son[x]!=0) dfs2(son[x],top[x]); for (int i=last[x];i!=0;i=side[i].next) if (side[i].y!=son[x] && side[i].y!=fa[x]) dfs2(side[i].y,side[i].y); } void change(int x,int l,int r,int po,int q) { if (po==l && l==r) { tree[x].ma=tree[x].sum=q; return; } int mid=(l+r)/2; if (po<=mid) change(x+x,l,mid,po,q); else change(x+x+1,mid+1,r,po,q); tree[x].sum=tree[x+x].sum+tree[x+x+1].sum; tree[x].ma=max(tree[x+x].ma,tree[x+x+1].ma); } int qumax(int x,int l,int r,int s,int e) { if (l==s && r==e) return tree[x].ma; int mid=(l+r)/2; if (e<=mid) return qumax(x+x,l,mid,s,e); else if (s>mid) return qumax(x+x+1,mid+1,r,s,e); else return max(qumax(x+x,l,mid,s,mid),qumax(x+x+1,mid+1,r,mid+1,e)); } int qusum(int x,int l,int r,int s,int e) { if (l==s && r==e) return tree[x].sum; int mid=(l+r)/2; if (e<=mid) return qusum(x+x,l,mid,s,e); else if (s>mid) return qusum(x+x+1,mid+1,r,s,e); else return qusum(x+x,l,mid,s,mid)+qusum(x+x+1,mid+1,r,mid+1,e); } void solmax(int x,int y) { int mx=-INF; while (top[x]!=top[y]) { if (dep[top[x]]<dep[top[y]]) swap(x,y); mx=max(mx,qumax(1,1,n,w[top[x]],w[x])); x=fa[top[x]]; } if (dep[x]>dep[y]) swap(x,y); mx=max(mx,qumax(1,1,n,w[x],w[y])); printf("%d\n",mx); } void solsum(int x,int y) { int su=0; while (top[x]!=top[y]) { if (dep[top[x]]<dep[top[y]]) swap(x,y); su+=qusum(1,1,n,w[top[x]],w[x]); x=fa[top[x]]; } if (dep[x]>dep[y]) swap(x,y); su+=qusum(1,1,n,w[x],w[y]); printf("%d\n",su); } int main() { freopen("1036.in","r",stdin); freopen("1036.out","w",stdout); init(); dfs1(1); dfs2(1,1); for (int i=1;i<=n;i++) change(1,1,n,w[i],num[i]); scanf("%d",&m); int x,y; for (int i=1;i<=m;i++) { scanf("%s%d%d",ch,&x,&y); if (ch[0]=='C') change(1,1,n,w[x],y); else if (ch[1]=='M') solmax(x,y); else solsum(x,y); } return 0; }
相关文章推荐
- bzoj1036: [ZJOI2008]树的统计Count
- BZOJ 1036 [ZJOI2008]树的统计Count (树链抛分)
- BZOJ 1036: [ZJOI2008]树的统计Count 树链剖分+线段树
- BZOJ 1036 [ZJOI2008]树的统计Count
- bzoj 1036: [ZJOI2008]树的统计Count
- [bzoj1036]:[ZJOI2008]树的统计Count(树链剖分)
- kyeremal-bzoj1036[ZJOI2008]-树的统计count-树链剖分
- [ZJOI2008]树的统计Count bzoj1036 树链剖分
- 树链剖分初讲 && [bzoj1036][ZJOI2008]树的统计Count
- 【bzoj1036】【树链剖分】 [ZJOI2008]树的统计Count
- BZOJ 1036: [ZJOI2008]树的统计Count 树链剖分
- BZOJ1036:[ZJOI2008]树的统计Count 树链剖分 / LCT
- AC日记——[ZJOI2008]树的统计Count bzoj 1036
- BZOJ 1036 [ZJOI2008]树的统计 Count 题解&代码
- 树链剖分教程 & bzoj 1036 [ZJOI2008] 树的统计 Count 题解
- 树链剖分(bzoj 1036: [ZJOI2008]树的统计Count)
- BZOJ 1036: [ZJOI2008]树的统计Count (树链剖分 + 线段树)
- BZOJ1036 [ZJOI2008]树的统计Count
- BZOJ 1036: [ZJOI2008]树的统计Count(树链剖分)
- BZOJ 1036: [ZJOI2008]树的统计Count 树链剖分