• P3384 【模板】树链剖分


    模板

      1 #include<algorithm>
      2 #include<iostream>
      3 #include<cstdlib>
      4 #include<cstring>
      5 #include<cstdio>
      6 #define Rint register int
      7 #define mem(a,b) memset(a,(b),sizeof(a))
      8 #define Temp template<typename T>
      9 using namespace std;
     10 typedef long long LL;
     11 Temp inline void read(T &x){
     12     x=0;T w=1,ch=getchar();
     13     while(!isdigit(ch)&&ch!='-')ch=getchar();
     14     if(ch=='-')w=-1,ch=getchar();
     15     while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar();
     16     x=x*w;
     17 }
     18 
     19 #define mid ((l+r)>>1)
     20 #define lson rt<<1,l,mid
     21 #define rson rt<<1|1,mid+1,r
     22 #define len (r-l+1)
     23 
     24 const int maxn=200000+10;
     25 int n,m,r,mod;
     26 //见题意 
     27 int e,beg[maxn],nex[maxn],to[maxn],w[maxn],wt[maxn];
     28 //链式前向星数组,w[]、wt[]初始点权数组 
     29 int a[maxn<<2],laz[maxn<<2];
     30 //线段树数组、lazy操作 
     31 int son[maxn],id[maxn],fa[maxn],cnt,dep[maxn],siz[maxn],top[maxn]; 
     32 //son[]重儿子编号,id[]新编号,fa[]父亲节点,cnt dfs_clock/dfs序,dep[]深度,siz[]子树大小,top[]当前链顶端节点 
     33 int res=0;
     34 //查询答案 
     35 
     36 inline void add(int x,int y){//链式前向星加边 
     37     to[++e]=y;
     38     nex[e]=beg[x];
     39     beg[x]=e;
     40 }
     41 //-------------------------------------- 以下为线段树 
     42 inline void pushdown(int rt,int lenn){
     43     laz[rt<<1]+=laz[rt];
     44     laz[rt<<1|1]+=laz[rt];
     45     a[rt<<1]+=laz[rt]*(lenn-(lenn>>1));
     46     a[rt<<1|1]+=laz[rt]*(lenn>>1);
     47     a[rt<<1]%=mod;
     48     a[rt<<1|1]%=mod;
     49     laz[rt]=0;
     50 }
     51 
     52 inline void build(int rt,int l,int r){
     53     if(l==r){
     54         a[rt]=wt[l];
     55         if(a[rt]>mod)a[rt]%=mod;
     56         return;
     57     }
     58     build(lson);
     59     build(rson);
     60     a[rt]=(a[rt<<1]+a[rt<<1|1])%mod;
     61 }
     62 
     63 inline void query(int rt,int l,int r,int L,int R){
     64     if(L<=l&&r<=R){res+=a[rt];res%=mod;return;}
     65     else{
     66         if(laz[rt])pushdown(rt,len);
     67         if(L<=mid)query(lson,L,R);
     68         if(R>mid)query(rson,L,R);
     69     }
     70 }
     71 
     72 inline void update(int rt,int l,int r,int L,int R,int k){
     73     if(L<=l&&r<=R){
     74         laz[rt]+=k;
     75         a[rt]+=k*len;
     76     }
     77     else{
     78         if(laz[rt])pushdown(rt,len);
     79         if(L<=mid)update(lson,L,R,k);
     80         if(R>mid)update(rson,L,R,k);
     81         a[rt]=(a[rt<<1]+a[rt<<1|1])%mod;
     82     }
     83 }
     84 //---------------------------------以上为线段树 
     85 inline int qRange(int x,int y){
     86     int ans=0;
     87     while(top[x]!=top[y]){//当两个点不在同一条链上 
     88         if(dep[top[x]]<dep[top[y]])swap(x,y);//把x点改为所在链顶端的深度更深的那个点
     89         res=0;
     90         query(1,1,n,id[top[x]],id[x]);//ans加上x点到x所在链顶端 这一段区间的点权和
     91         ans+=res;
     92         ans%=mod;//按题意取模 
     93         x=fa[top[x]];//把x跳到x所在链顶端的那个点的上面一个点
     94     }
     95     //直到两个点处于一条链上
     96     if(dep[x]>dep[y])swap(x,y);//把x点深度更深的那个点
     97     res=0;
     98     query(1,1,n,id[x],id[y]);//这时再加上此时两个点的区间和即可
     99     ans+=res;
    100     return ans%mod;
    101 }
    102 
    103 inline void updRange(int x,int y,int k){//同上 
    104     k%=mod;
    105     while(top[x]!=top[y]){
    106         if(dep[top[x]]<dep[top[y]])swap(x,y);
    107         update(1,1,n,id[top[x]],id[x],k);
    108         x=fa[top[x]];
    109     }
    110     if(dep[x]>dep[y])swap(x,y);
    111     update(1,1,n,id[x],id[y],k);
    112 }
    113 
    114 inline int qSon(int x){
    115     res=0;
    116     query(1,1,n,id[x],id[x]+siz[x]-1);//子树区间右端点为id[x]+siz[x]-1 
    117     return res;
    118 }
    119 
    120 inline void updSon(int x,int k){//同上 
    121     update(1,1,n,id[x],id[x]+siz[x]-1,k);
    122 }
    123 
    124 inline void dfs1(int x,int f,int deep){//x当前节点,f父亲,deep深度 
    125     dep[x]=deep;//标记每个点的深度 
    126     fa[x]=f;//标记每个点的父亲 
    127     siz[x]=1;//标记每个非叶子节点的子树大小 
    128     int maxson=-1;//记录重儿子的儿子数 
    129     for(Rint i=beg[x];i;i=nex[i]){
    130         int y=to[i];
    131         if(y==f)continue;//若为父亲则continue 
    132         dfs1(y,x,deep+1);//dfs其儿子 
    133         siz[x]+=siz[y];//把它的儿子数加到它身上 
    134         if(siz[y]>maxson)son[x]=y,maxson=siz[y];//标记每个非叶子节点的重儿子编号 
    135     }
    136 }
    137 
    138 inline void dfs2(int x,int topf){//x当前节点,topf当前链的最顶端的节点 
    139     id[x]=++cnt;//标记每个点的新编号 
    140     wt[cnt]=w[x];//把每个点的初始值赋到新编号上来 
    141     top[x]=topf;//这个点所在链的顶端 
    142     if(!son[x])return;//如果没有儿子则返回 
    143     dfs2(son[x],topf);//按先处理重儿子,再处理轻儿子的顺序递归处理 
    144     for(Rint i=beg[x];i;i=nex[i]){
    145         int y=to[i];
    146         if(y==fa[x]||y==son[x])continue;
    147         dfs2(y,y);//对于每一个轻儿子都有一条从它自己开始的链 
    148     }
    149 }
    150 
    151 int main(){
    152     read(n);read(m);read(r);read(mod);
    153     for(Rint i=1;i<=n;i++)read(w[i]);
    154     for(Rint i=1;i<n;i++){
    155         int a,b;
    156         read(a);read(b);
    157         add(a,b);add(b,a);
    158     }
    159     dfs1(r,0,1);
    160     dfs2(r,r);
    161     build(1,1,n);
    162     while(m--){
    163         int k,x,y,z;
    164         read(k);
    165         if(k==1){
    166             read(x);read(y);read(z);
    167             updRange(x,y,z);
    168         }
    169         else if(k==2){
    170             read(x);read(y);
    171             printf("%d
    ",qRange(x,y));
    172         }
    173         else if(k==3){
    174             read(x);read(y);
    175             updSon(x,y);
    176         }
    177         else{
    178             read(x);
    179             printf("%d
    ",qSon(x));
    180         }
    181     }
    182 }
  • 相关阅读:
    SQL清除数据库日志方法
    TFS服务器及服务帐号迁域的处理
    about WBS
    ASP.NET URL Rewrite. URL重写
    查看SQL Server中某数据库下每个表占用的空间大小
    [西安招聘] 微软西安分公司 招聘.NET软件工程师,MOSS开发工程师
    企业微信的数据打通
    常见Post请求与实现
    Python解释器与__pycache__文件夹的生成
    微信开放平台OpenID与UnionID的区别
  • 原文地址:https://www.cnblogs.com/hahaha2124652975/p/11231056.html
Copyright © 2020-2023  润新知