• [模板]树链剖分


    题目描述

    如题,已知一棵包含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为根节点的子树内所有节点值之和

    输入输出格式

    输入格式

      第一行包含4个正整数N、M、R、P,分别表示树的结点个数、操作个数、根节点序号和取模数(即所有的输出结果均对此取模)。

      接下来一行包含N个非负整数,分别依次表示各个节点上初始的数值。

      接下来N-1行每行包含两个整数x、y,表示点x和点y之间连有一条边(保证无环且连通)

      接下来M行每行包含若干个正整数,每行表示一个操作,格式如下:

      操作1: 1 x y z

      操作2: 2 x y

      操作3: 3 x z

      操作4: 4 x

    输出格式

      输出包含若干行,分别依次表示每个操作2或操作4所得的结果(对P取模)

      1 #include<cstdio>
      2 #define ll long long
      3 using namespace std;
      4 const int maxn=1e5+5;
      5 int v[maxn],head[maxn];
      6 int mod,num,ord;
      7 struct Edge{
      8     int to,next;
      9 }edge[maxn<<1];
     10 struct Tree{
     11     int v,lazy; 
     12 }tree[maxn<<2];
     13 struct cp{
     14     int v,size,son,dep,ord,top,fa;
     15 }e[maxn];
     16 inline void add(int u,int v){
     17     edge[++num].to=v;
     18     edge[num].next=head[u];
     19     head[u]=num;
     20 }
     21 void build(int x,int s,int t){
     22     if(s==t) tree[x].v=v[s];
     23     else{
     24         int mid=s+t>>1;
     25         build(x<<1,s,mid);
     26         build(x<<1|1,mid+1,t);
     27         tree[x].v=tree[x<<1].v+tree[x<<1|1].v;
     28     }
     29 }
     30 void swap(int &x,int &y){
     31     x^=y^=x^=y;
     32 }
     33 void dfs1(int x){
     34     int size=0;
     35     e[x].size=1;
     36     for(int i=head[x];i;i=edge[i].next){
     37         int v=edge[i].to;
     38         if(v==e[x].fa) continue;
     39         e[v].fa=x;
     40         e[v].dep=e[x].dep+1;
     41         dfs1(v);
     42         e[x].size+=e[v].size;
     43         if(e[v].size>size) size=e[v].size,e[x].son=v;
     44     }
     45 }
     46 void dfs2(int x){
     47     e[x].ord=++ord;//ord为dfs序; 
     48     v[ord]=e[x].v;
     49     if(e[e[x].fa].son!=x) e[x].top=x;
     50     else e[x].top=e[e[x].fa].top;
     51     if(e[x].son) dfs2(e[x].son);
     52     for(int i=head[x];i;i=edge[i].next)
     53         if(e[x].fa!=edge[i].to&&e[x].son!=edge[i].to) dfs2(edge[i].to);
     54 }
     55 inline void pushdown(int x,int s,int t){
     56     if(!tree[x].lazy) return ;
     57     int mid=s+t>>1;
     58     tree[x<<1].lazy+=tree[x].lazy;
     59     tree[x<<1|1].lazy+=tree[x].lazy;
     60     tree[x<<1].v=((ll)(tree[x<<1].v+tree[x].lazy*(mid-s+1)))%mod;
     61     tree[x<<1|1].v=((ll)(tree[x<<1|1].v+tree[x].lazy*(t-mid)))%mod;
     62     tree[x].lazy=0;
     63 }
     64 void update(int x,int ns,int nt,int s,int t,int add){
     65     if(nt<s||ns>t) return ;
     66     if(ns>=s&&nt<=t){
     67         tree[x].lazy+=add;
     68         tree[x].v=((ll)tree[x].v+add*(nt-ns+1))%mod;
     69         return ;
     70     }
     71     pushdown(x,ns,nt);
     72     int mid=ns+nt>>1;
     73     update(x<<1,ns,mid,s,t,add);
     74     update(x<<1|1,mid+1,nt,s,t,add);
     75     tree[x].v=(tree[x<<1].v+tree[x<<1|1].v)%mod;
     76 }
     77 int query(int x,int ns,int nt,int s,int t){
     78     if(nt<s||ns>t) return 0;
     79     if(ns>=s&&nt<=t) return tree[x].v;
     80     pushdown(x,ns,nt);
     81     int mid=ns+nt>>1;
     82     return (query(x<<1,ns,mid,s,t)+query(x<<1|1,mid+1,nt,s,t))%mod;
     83 }
     84 inline int read(){
     85     char ch=getchar();
     86     int x=0,f=1;
     87     while(ch<'0'||ch>'9'){
     88         if(ch=='-') f=-1;
     89         ch=getchar();
     90     }
     91     while(ch>='0'&&ch<='9'){
     92         x=(x<<1)+(x<<3)+(ch^48);
     93         ch=getchar();
     94     }
     95     return x*f;
     96 }
     97 int main(){
     98     int n,m,r,x,y,z,f;
     99     n=read(),m=read(),r=read(),mod=read();
    100     for(int i=1;i<=n;i++) e[i].v=read();
    101     for(int i=1;i<n;i++){
    102         x=read(),y=read();
    103         add(x,y),add(y,x);
    104     }
    105     dfs1(r),dfs2(r);
    106     build(1,1,n);
    107     while(m--){
    108         f=read(),x=read();
    109         if(f==1){//表示将树从x到y结点最短路径上所有节点的值都加上z
    110             y=read(),z=read();
    111             while(e[x].top!=e[y].top){
    112                 if(e[e[x].top].dep<e[e[y].top].dep) swap(x,y);
    113                 update(1,1,n,e[e[x].top].ord,e[x].ord,z);
    114                 x=e[e[x].top].fa;
    115             }
    116             if(e[x].ord>e[y].ord) swap(x,y);
    117             update(1,1,n,e[x].ord,e[y].ord,z);
    118         }
    119         if(f==2){//表示求树从x到y结点最短路径上所有节点的值之和
    120             int s=0;
    121             y=read();
    122             while(e[x].top!=e[y].top){
    123                 if(e[e[x].top].dep<e[e[y].top].dep) swap(x,y);
    124                 s+=query(1,1,n,e[e[x].top].ord,e[x].ord);
    125                 x=e[e[x].top].fa;
    126             }
    127             if(e[x].ord>e[y].ord) swap(x,y);
    128             printf("%d
    ",(s+query(1,1,n,e[x].ord,e[y].ord))%mod);
    129         }
    130         if(f==3){//表示将以x为根节点的子树内所有节点值都加上z
    131             y=read();
    132             update(1,1,n,e[x].ord,e[x].ord+e[x].size-1,y);
    133         }
    134         if(f==4)//表示求以x为根节点的子树内所有节点值之和
    135             printf("%d
    ",query(1,1,n,e[x].ord,e[x].ord+e[x].size-1));
    136     }
    137     return 0;
    138 }
    树链剖分
  • 相关阅读:
    Silverlight开发历程—(用C#来绘制图形)
    Silverlight之dispatcherTimer 与 线程
    Silverlight开发历程—RenderTransform特效(TranslateTransform,RotateTransform,ScaleTransform,skewTransform)
    百度程序员猝死 是否过劳死引发争论
    10款优秀的HTML5开发工具
    Silverlight开发历程—(绘制报表)
    IT的哥一样是传说!
    Silverlight开发历程—(布局控件Canvas)
    Silverlight开发历程—(利用C#代码制作取色器)
    Silverlight开发历程—(画刷与着色之线性渐变画刷)
  • 原文地址:https://www.cnblogs.com/RisingGods/p/9126421.html
Copyright © 2020-2023  润新知