BZOJ 1036: [ZJOI2008]树的统计Count 【树链剖分】
2015-03-20 14:57
429 查看
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”的形式给出。 对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。
Output
对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。
Sample Input
41 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
41
2
2
10
6
5
6
5
16
HINT
Source
思路:唔说是树分治,其实裸的树链剖分,这里总结一下树链剖分吧,基本思路就是把树上的路径分成两种,一般是轻重链剖分,然后重链在线段树上查,轻链直接向父亲条的做法,当然由于它们同时存在于线段树中,所以两步是可以合并的,树剖的思想大概就是这样,用到的数组也就是father[]记录父亲,top[]记录重链顶部的节点,id[]记录每个节点在线段树中的位置三个而已,至于其它像size,son之类的只是为了求出前面三个数组所开的辅助数组,一般的话第一个dfs找重儿子,重边,第二个dfs将前面找到的重边连起来变成重链求出top
#include<iostream> #include<cstdio> #define maxn 60000 using namespace std; int w[maxn],head[maxn],point[maxn],next[maxn*2],top[maxn],id[maxn],size_k[maxn],pos=0,now; int father[maxn],son[maxn],deep[maxn]; struct T { int max_x;int sum_x; T(){max_x=-0x3f3f3f3f;sum_x=0;} }tree[maxn*4]; T work(T x,T y) { T ans; ans.max_x=max(x.max_x,y.max_x); ans.sum_x=x.sum_x+y.sum_x; return ans; } T query(int node,int l,int r,int ql,int qr) { if(ql<=l && r<=qr)return tree[node]; int mid=(l+r)>>1;T ans; if(ql<mid)ans=query(node*2,l,mid,ql,qr); if(mid<qr)ans=work(ans,query(node*2+1,mid,r,ql,qr)); return ans; } void update(int node,int l,int r,int p,int x){ if(l+1==r){ tree[node].max_x=x;tree[node].sum_x=x;return ; } int mid=(l+r)>>1; if(p<mid)update(node*2,l,mid,p,x); else update(node*2+1,mid,r,p,x); tree[node]=work(tree[node*2],tree[node*2+1]); return ; } void add(int x,int y){ next[++now]=head[x];head[x]=now;point[now]=y; } void dfs(int k,int fa) { deep[k]=deep[fa]+1; father[k]=fa;size_k[k]=1; int max_x=-1;son[k]=-1; for(int i=head[k];i;i=next[i]) { if(point[i]==fa)continue; dfs(point[i],k); size_k[k]+=size_k[point[i]]; if(size_k[point[i]]>max_x) { max_x=size_k[point[i]]; son[k]=point[i]; } } } void dfs2(int k,int fa,int pa) { id[k]=++pos;top[k]=pa; if(son[k]!=-1)dfs2(son[k],k,pa); for(int i=head[k];i;i=next[i])if(point[i]!=fa && point[i]!=son[k])dfs2(point[i],k,point[i]); } T find(int x,int y) { int fx=top[x],fy=top[y]; T tmp; while(fx!=fy) { if(deep[fx]<deep[fy])swap(fx,fy),swap(x,y); tmp=work(tmp,query(1,1,pos+1,id[fx],id[x]+1)); x=father[fx];fx=top[x]; } if(deep[x]<deep[y])swap(x,y); return work(tmp,query(1,1,pos+1,id[y],id[x]+1)); } int main() { int n,x,y,q; char ch[100]; scanf("%d",&n); for(int i=1;i<n;i++) { scanf("%d%d",&x,&y); add(x,y);add(y,x); } for(int i=1;i<=n;i++)scanf("%d",&w[i]); scanf("%d",&q); dfs(1,0);dfs2(1,1,1); for(int i=1;i<=n;i++)update(1,1,pos+1,id[i],w[i]); while(q--) { scanf("%s%d%d",ch,&x,&y); if(ch[1]=='S') { T u=find(x,y);printf("%d\n",u.sum_x); } if(ch[1]=='M') { T u=find(x,y);printf("%d\n",u.max_x); } if(ch[1]=='H')update(1,1,pos+1,id[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 树链剖分+线段树
- BZOJ 1036: [ZJOI2008]树的统计Count(树链剖分 点权)
- 【BZOJ 1036】[ZJOI2008]树的统计Count 【树链剖分+线段树】
- BZOJ1036:[ZJOI2008]树的统计Count 树链剖分 / LCT
- [树链剖分] BZOJ1036: [ZJOI2008]树的统计Count
- BZOJ1036 [ZJOI2008]树的统计Count 树链剖分
- BZOJ 1036([ZJOI2008]树的统计Count-树链剖分[成熟版])
- bzoj 1036: [ZJOI2008]树的统计Count (树链剖分)
- bzoj 1036: [ZJOI2008]树的统计Count——树链剖分
- Bzoj 1036: [ZJOI2008]树的统计Count 树链剖分,LCT
- [ZJOI2008]树的统计Count bzoj1036 树链剖分
- BZOJ 1036: [ZJOI2008]树的统计Count 树链剖分
- BZOJ.1036 [ZJOI2008]树的统计Count ( 点权树链剖分 线段树维护和与最值)
- [bzoj1036][ZJOI2008]树的统计Count 树链剖分
- BZOJ 1036: [ZJOI2008]树的统计Count 树链剖分