bzoj 1036 [ZJOI2008]树的统计Count 树链剖分模板

1036: [ZJOI2008]树的统计Count

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 18615  Solved: 7598
[Submit][Status][Discuss]

Description

  一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成
一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I
II. 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

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
-------------------------------------------------------------------------------------------------
树链剖分模板题
看黄学长的博客才会的
个人理解:当你想要维护一棵每个点都有权值的树,让这棵树支持在线修改点权值、求点到点的路径上点权和or最大/小值时,就用树链剖分。
剖分的方法有多种,这里用的轻重链。
其原理就是:先找出这棵树的重链,然后按照轻重链给结点重新编号(一条重链上的点的新编号是连续的),然后再按照新编号将树上的所有结点压入数据结构,这里压入一棵线段树。
 后面就的操作就在线段树上进行,将路径尽量往重链上靠。
 
 
  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<stdlib.h>
  4 #include<iostream>
  5 #define maxn 233333
  6 #define lson ro<<1
  7 #define rson ro<<1|1
  8 #define inf 1e9
  9 using namespace std;
 10 struct node{int to,next;};
 11 struct rode{int l,r,sum,mx;};
 12 node e[maxn];
 13 rode tr[maxn];
 14 int n,v[30010],pos[30010],dep[30010],pre[maxn],cnt,fa[30010],size[30010],sz,bl[30010],mxx,an,m;
 15 int read();
 16 void insert(int,int);
 17 void build(int,int,int);
 18 void pushup(int);
 19 void dfs1(int);
 20 void dfs2(int,int);
 21 void querymx(int,int,int);
 22 void querysum(int,int,int);
 23 int solvemx(int,int);
 24 int solvesum(int,int);
 25 void change(int,int,int);
 26 int main(){
 27     n=read();
 28     for(int i=1;i<n;i++)insert(read(),read());
 29     for(int i=1;i<=n;i++)v[i]=read();
 30     dfs1(1);
 31     dfs2(1,1);
 32     build(1,n,1);
 33     for(int i=1;i<=n;i++) change(pos[i],v[i],1);
 34     m=read();
 35     for(int i=1;i<=m;i++){
 36         char cuan[12];
 37         scanf(" %s",cuan);
 38         if(cuan[1]=='H'){
 39             int x=read(),k=read();
 40             change(pos[x],k,1);
 41         }
 42         else if(cuan[1]=='M') printf("%d\n",solvemx(read(),read()));
 43         else printf("%d\n",solvesum(read(),read()));
 44     }
 45     return 0;
 46 }
 47 int read(){
 48     int ans=0,f=1;char c=getchar();
 49     while('0'>c||c>'9'){if(c=='-')f=-1;c=getchar();}
 50     while('0'<=c&&c<='9')ans=ans*10+c-48,c=getchar();return ans*f;
 51 }
 52 void insert(int x,int y){
 53     e[++cnt].to=y;e[cnt].next=pre[x];pre[x]=cnt;
 54     e[++cnt].to=x;e[cnt].next=pre[y];pre[y]=cnt;
 55 }
 56 void build(int l,int r,int ro){
 57     tr[ro].l=l;tr[ro].r=r;
 58     if(l==r) return;
 59     int mid=(l+r)>>1;
 60     build(l,mid,lson);build(mid+1,r,rson);
 61 }
 62 void pushup(int ro){
 63     tr[ro].sum=tr[lson].sum+tr[rson].sum;
 64     tr[ro].mx=max(tr[lson].mx,tr[rson].mx);
 65 }
 66 void dfs1(int x){
 67     size[x]=1;
 68     for(int i=pre[x];i;i=e[i].next){
 69         int to=e[i].to;
 70         if(fa[x]==to)continue;
 71         fa[to]=x;
 72         dep[to]=dep[x]+1;
 73         dfs1(to);
 74         size[x]+=size[to];
 75     }
 76 }
 77 void dfs2(int x,int chain){
 78     int k=0;
 79     pos[x]=++sz;
 80     bl[x]=chain;
 81     for(int i=pre[x];i;i=e[i].next)
 82        if(dep[e[i].to]>dep[x]&&size[k]<size[e[i].to])
 83           k=e[i].to;
 84     if(k==0)return;
 85     dfs2(k,chain);
 86     for(int i=pre[x];i;i=e[i].next)
 87        if(dep[e[i].to]>dep[x]&&k!=e[i].to)
 88           dfs2(e[i].to,e[i].to);
 89 }
 90 void change(int x,int k,int ro){
 91     if(tr[ro].r==tr[ro].l){
 92         tr[ro].sum=tr[ro].mx=k;
 93         return;
 94     }
 95     int mid=(tr[ro].r+tr[ro].l)>>1;
 96     if(x<=mid) change(x,k,lson);
 97     else change(x,k,rson);
 98     pushup(ro);
 99 }
100 void querymx(int l,int r,int ro){
101     if(l<=tr[ro].l&&tr[ro].r<=r){
102         mxx=max(mxx,tr[ro].mx);
103         return;
104     }
105     int mid=(tr[ro].l+tr[ro].r)>>1;
106     if(l<=mid) querymx(l,r,lson);
107     if(r>mid)  querymx(l,r,rson);
108 }
109 void querysum(int l,int r,int ro){
110     if(l<=tr[ro].l&&tr[ro].r<=r){
111         an+=tr[ro].sum;
112         return;
113     }
114     int mid=(tr[ro].l+tr[ro].r)>>1;
115     if(l<=mid) querysum(l,r,lson);
116     if(r>mid)  querysum(l,r,rson);
117 }
118 int solvemx(int x,int y){
119     int mxs=-inf;
120     while(bl[x]!=bl[y]){
121         if(dep[bl[x]]<dep[bl[y]])swap(x,y);
122         mxx=-inf;querymx(pos[bl[x]],pos[x],1);
123         mxs=max(mxs,mxx);
124         x=fa[bl[x]];
125     }
126     if(pos[x]>pos[y])swap(x,y);
127     mxx=-inf;querymx(pos[x],pos[y],1);
128     mxs=max(mxs,mxx);
129     return mxs;
130 }
131 int solvesum(int x,int y){
132     int sum=0;
133     while(bl[x]!=bl[y]){
134         if(dep[bl[x]]<dep[bl[y]])swap(x,y);
135         an=0;querysum(pos[bl[x]],pos[x],1);
136         sum+=an;
137         x=fa[bl[x]];
138     }
139     if(pos[x]>pos[y])swap(x,y);
140     an=0;querysum(pos[x],pos[y],1);
141     sum+=an;
142     return sum;
143 }
树链剖分

 

posted @ 2017-09-21 22:06  lpl_bys  阅读(183)  评论(0编辑  收藏  举报