• 洛谷P3384 树链剖分


    如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作:

    操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z

    操作2: 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和

    操作3: 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z

    操作4: 格式: 4 x 表示求以x为根节点的子树内所有节点值之和

                        --by洛谷



    一听名字就知道是模板;

    有关树链剖分的内容

    对子树操作,可理解为对dfs序上fa开头长度为子树size的区间操作;

    代码如下:

      1 #include<cstdio>
      2 using namespace std;
      3 int n,m,r,L,R;
      4 int p,Z;
      5 int dis[100001];
      6 int ltree[400001];
      7 int      lz[400001];
      8 int dep[100001],fa[100001],hine[100001],size[100001];
      9 int top[100001],a[100001],rank[100001];
     10 struct ss{
     11     int to,next;
     12 }x[200001];
     13 int first[200001],num;
     14 void build(int ,int );
     15 void dfs_1(int );
     16 void dfs_2(int ,int );
     17 void up(int );
     18 void down(int ,int ,int );
     19 void builine(int ,int ,int );
     20 void swap(int&,int&);
     21 void work1(int );
     22 void work2(int );
     23 void add(int ,int ,int );
     24 int sum(int ,int ,int );
     25 int main()
     26 {
     27     int i,j,k;
     28     scanf("%d%d%d%d",&n,&m,&r,&p);
     29     for(i=1;i<=n;i++)
     30         scanf("%d",&dis[i]),dis[i]%=p,hine[i]=i;
     31     for(i=1;i<=n-1;i++){
     32         scanf("%d%d",&j,&k);
     33         build(j,k);
     34         build(k,j);
     35     }
     36     dep[r]=1;
     37     dfs_1(r);
     38     num=0;
     39     dfs_2(r,r);
     40     num=0;
     41     builine(1,n,1);
     42     for(i=1;i<=m;i++){
     43         scanf("%d",&j);
     44         if(j<=2)work1(j);
     45         else    work2(j-2);
     46     }
     47 }
     48 void build(int f,int t){
     49     x[++num].next=first[f];
     50     x[num].to=t;
     51     first[f]=num;
     52 }
     53 void dfs_1(int now){
     54     int j=first[now];
     55     while(j){
     56         if(!dep[x[j].to]){
     57             dep[x[j].to]=dep[now]+1;
     58             fa[x[j].to]=now;
     59             dfs_1(x[j].to);
     60             size[now]+=size[x[j].to];
     61             if(hine[now]==now||size[x[j].to]>size[hine[now]])
     62                 hine[now]=x[j].to;
     63         }
     64         j=x[j].next;
     65     }
     66     size[now]++;
     67 }
     68 void dfs_2(int now,int top_now){
     69     int j=first[now];
     70     top[now]=top_now;
     71     a[++num]=now;
     72     rank[now]=num;
     73     if(hine[now]!=now)
     74         dfs_2(hine[now],top_now);
     75     while(j){
     76         if(dep[x[j].to]==dep[now]+1&&x[j].to!=hine[now])
     77             dfs_2(x[j].to,x[j].to);
     78         j=x[j].next;
     79     }
     80 }
     81 void up(int nu){
     82     ltree[nu]=ltree[nu<<1]+ltree[nu<<1|1];
     83 }
     84 void down(int l,int r,int nu){
     85     if(!lz[nu])return ;
     86     int mid=(l+r)>>1;
     87     lz[nu<<1]=(lz[nu<<1]+lz[nu])%p;
     88     lz[nu<<1|1]=(lz[nu<<1|1]+lz[nu])%p;
     89     ltree[nu<<1]=(ltree[nu<<1]+lz[nu]*(mid-l+1))%p;
     90     ltree[nu<<1|1]=(ltree[nu<<1|1]+lz[nu]*(r-mid))%p;
     91     lz[nu]=0;
     92 }
     93 void builine(int l,int r,int nu){
     94     if(l==r){
     95         ltree[nu]=dis[a[++num]];
     96         return;
     97     }
     98     int mid=(l+r)>>1;
     99     builine(l,mid,nu<<1);
    100     builine(mid+1,r,nu<<1|1);
    101     up(nu);
    102 }
    103 void swap(int&a,int&b){
    104     int c=a;a=b;b=c;
    105 }
    106 void work1(int x){
    107     int u,v,ans=0;
    108     scanf("%d%d",&u,&v);
    109     if(x==1)scanf("%d",&Z);
    110     while(top[u]!=top[v]){
    111         if(dep[top[u]]>dep[top[v]])
    112             L=rank[top[u]],R=rank[u],u=fa[top[u]];
    113         else
    114             L=rank[top[v]],R=rank[v],v=fa[top[v]];
    115         if(x==1)
    116             add(1,n,1);
    117         else
    118             ans=(ans+sum(1,n,1))%p;
    119     }
    120 //    if(u!=v){
    121     if(dep[u]>dep[v])
    122         swap(u,v);
    123     L=rank[u];R=rank[v];
    124     if(x==1)
    125         add(1,n,1);
    126     else
    127         ans=(ans+sum(1,n,1))%p;
    128 //    }
    129     if(x==2)
    130         printf("%d
    ",ans);
    131 }
    132 void work2(int x){
    133     int ans=0,i;
    134     scanf("%d",&i);
    135     L=rank[i];R=L+size[i]-1;
    136     if(x==1)scanf("%d",&Z);
    137         if(x==1)
    138             add(1,n,1);
    139         else
    140             ans=(ans+sum(1,n,1))%p,printf("%d
    ",ans);
    141 }
    142 void add(int l,int r,int nu){
    143     if(L<=l&&r<=R){
    144         ltree[nu]=(ltree[nu]+(r-l+1)*Z)%p;
    145         lz[nu]=(lz[nu]+Z)%p;
    146         return ;
    147     }
    148     int mid=(l+r)>>1;
    149     down(l,r,nu);
    150     if(L<=mid)
    151         add(l,mid,nu<<1);
    152     if(R>mid)
    153         add(mid+1,r,nu<<1|1);
    154     up(nu);
    155 }
    156 int sum(int l,int r,int nu){
    157     if(L<=l&&r<=R)
    158         return ltree[nu];
    159     int mid=(l+r)>>1,ans=0;
    160     down(l,r,nu);
    161     if(L<=mid)
    162         ans=(ans+sum(l,mid,nu<<1))%p;
    163     if(R>mid)
    164         ans=(ans+sum(mid+1,r,nu<<1|1))%p;
    165     return ans;
    166 }

    祝AC哟!

  • 相关阅读:
    文件较验及Google Gson的使用
    SQLite数据库操作
    错误收集
    【记录】Linux安装JDK详细步骤
    【原创】RPM安装软件时解决依赖性问题(自动解决依赖型)
    【原创】rman备份出现ORA-19625
    【原创】rman 全库备份脚本
    【原创】TimeSten安装与配置
    【原创】查询占CPU高的oracle进程
    【参考】查找Oracle最高的几个等待事件以及锁的信息
  • 原文地址:https://www.cnblogs.com/nietzsche-oier/p/6386278.html
Copyright © 2020-2023  润新知