【ZJOI2008】树的统计

一道普通的树链剖分模板题,注意细节即可

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 typedef long long ll;
  5 inline int read() {
  6     int ret=0,f=1;
  7     char c=getchar();
  8     while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
  9     while(c<='9'&&c>='0') ret=ret*10+c-'0',c=getchar();
 10     return ret*f;
 11 }
 12 using namespace std;
 13 int n,q;
 14 struct edge {
 15     int next,to;
 16 }a[30010<<1];
 17 int head[30010<<1],num,val[30010];
 18 int fa[30010],size[30010],d[30010],son[30010],top[30010];
 19 int seg[30010],rev[30010],sum[30010<<2],maxx[30010<<2];
 20 int retsum,retmax;
 21 char in[11];
 22 inline void add(int from,int to) {
 23     a[++num].next=head[from]; a[num].to=to; head[from]=num;
 24     swap(from,to);
 25     a[++num].next=head[from]; a[num].to=to; head[from]=num;
 26 }
 27 inline void pushup(int now) {
 28     sum[now]=sum[now<<1]+sum[now<<1|1];
 29     maxx[now]=max(maxx[now<<1],maxx[now<<1|1]);
 30 }
 31 void dfs1(int u,int f) {
 32     size[u]=1;
 33     fa[u]=f;
 34     d[u]=d[f]+1;
 35     for(int i=head[u];i;i=a[i].next) {
 36         int v=a[i].to;
 37         if(v==f) continue ;
 38         dfs1(v,u);
 39         size[u]+=size[v];
 40         if(size[v]>size[son[u]]) son[u]=v;
 41     }
 42 }
 43 void dfs2(int u,int f) {
 44     if(son[u]) {
 45         seg[son[u]]=++seg[0];
 46         top[son[u]]=top[u];
 47         rev[seg[0]]=son[u];
 48         dfs2(son[u],u);
 49     }
 50     for(int i=head[u];i;i=a[i].next) {
 51         int v=a[i].to;
 52         if(!top[v]) {
 53             seg[v]=++seg[0];
 54             rev[seg[0]]=v;
 55             top[v]=v;
 56             dfs2(v,u);
 57         }
 58     }
 59 }
 60 void build(int now,int l,int r) {
 61     if(l==r) {
 62         sum[now]=maxx[now]=val[rev[l]];
 63         return ;
 64     }
 65     int mid=l+r>>1;
 66     build(now<<1,l,mid);
 67     build(now<<1|1,mid+1,r);
 68     pushup(now);
 69 }
 70 void updata(int now,int l,int r,int x,int v) {
 71     if(l==r) {
 72         sum[now]=v;
 73         maxx[now]=v;
 74         return ;
 75     }
 76     int mid=l+r>>1;
 77     if(x<=mid) updata(now<<1,l,mid,x,v);
 78     else updata(now<<1|1,mid+1,r,x,v);
 79     pushup(now);
 80 }
 81 void query(int now,int l,int r,int x,int y) {
 82     if(x<=l&&r<=y) {
 83         retsum+=sum[now];
 84         retmax=max(retmax,maxx[now]);
 85         return ;
 86     }
 87     int mid=l+r>>1;
 88     if(x<=mid) query(now<<1,l,mid,x,y);
 89     if(y>mid) query(now<<1|1,mid+1,r,x,y);
 90 }
 91 void find(int x,int y) {
 92     while(top[x]!=top[y]) {
 93         if(d[top[x]]<d[top[y]]) swap(x,y);
 94         query(1,1,seg[0],seg[top[x]],seg[x]);
 95         x=fa[top[x]];    
 96     }
 97     if(d[x]>d[y]) swap(x,y);
 98     query(1,1,seg[0],seg[x],seg[y]);
 99 }
100 int main() {
101     n=read();
102     for(int i=1;i<n;i++) add(read(),read());
103     for(int i=1;i<=n;i++) val[i]=read();
104     dfs1(1,0);
105     seg[0]=seg[1]=top[1]=rev[1]=1;
106     dfs2(1,0);
107     build(1,1,seg[0]);
108     q=read();
109     while(q--) {
110         scanf("%s",in+1);
111         int x=read(),y=read();
112         if(in[1]=='C') updata(1,1,seg[0],seg[x],y);
113         else {
114             retsum=0;
115             retmax=-999999999;
116             find(x,y);
117             if(in[2]=='M') printf("%d\n",retmax);
118             else printf("%d\n",retsum);
119         }
120     }
121     return 0;
122 }

几个易错点总结:

  1. 树链剖分的求解过程实质上是线段树,所以线段树维护的相关数组应开4倍空间
  2. 注意区分seg与rev的含义
  3. retmax,retsum赋初值
  4. 注意第95行(个人易错)
posted @ 2019-03-09 14:39  AD_shl  阅读(325)  评论(0编辑  收藏  举报