zoukankan      html  css  js  c++  java
  • 【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
    ",retmax);
    118             else printf("%d
    ",retsum);
    119         }
    120     }
    121     return 0;
    122 }

    几个易错点总结:

    1. 树链剖分的求解过程实质上是线段树,所以线段树维护的相关数组应开4倍空间
    2. 注意区分seg与rev的含义
    3. retmax,retsum赋初值
    4. 注意第95行(个人易错)
  • 相关阅读:
    cogs1538 [AHOI2005]LANE 航线规划
    cogs468 [NOI2010]超级钢琴
    [国家集训队2011]数颜色
    动态点分治总结
    点分治总结
    数论知识总结-欧拉函数
    BZOJ2683 简单题
    COGS1871 [国家集训队2011]排队(魏铭)
    LUOGU3278 [SCOI2013]多项式的运算
    BZOJ4491 我也不知道题目名字是什么
  • 原文地址:https://www.cnblogs.com/shl-blog/p/10500726.html
Copyright © 2011-2022 走看看