• 树链剖分模板


     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为根节点的子树内所有节点值之和

    输入输出格式

    输入格式:

    第一行包含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:
    5 5 2 24
    7 3 7 8 0 
    1 2
    1 5
    3 1
    4 1
    3 4 2
    3 2 2
    4 5
    1 5 1 3
    2 1 3
    输出样例#1:
    2
    21

    说明

    时空限制:1s,128M

    数据规模:

    对于30%的数据:N<=10,M<=10

    对于70%的数据:N<=1000,M<=1000

    对于100%的数据:N<=100000,M<=100000

    (其实,纯随机生成的树LCA+暴力是能过的,可是,你觉得可能是纯随机的么233)

    样例说明:

    树的结构如下:

    各个操作如下:

    故输出应依次为2、21(重要的事情说三遍:记得取模)

    半夜不适合敲代码,尤其这种结构体数组中多个定义的……

    码程四十分钟,调程三小时……

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 using namespace std;
      6 int n,m,r,p,cnt,tot;
      7 int val[100010],head[100010];
      8 struct data{
      9     int next,to;
     10 }edge[200010];
     11 struct dt{
     12     int fa,son,size,deep,top,num,end;
     13     //son 重儿子 
     14     //size 子结点个数
     15     //top  当前结点所在链的顶结点 
     16 }tree[100010];
     17 struct tr{
     18     int sum,mark;
     19 }segtree[400010];
     20 void add_edge(int start,int ed){
     21     edge[++cnt].next=head[start];
     22     edge[cnt].to=ed;
     23     head[start]=cnt;
     24     return;
     25 }
     26 void dfs_weight(int u){
     27     tree[u].size=1;
     28     tree[u].son=0;
     29     for(int i=head[u];i;i=edge[i].next)
     30         if(edge[i].to!=tree[u].fa){
     31             tree[edge[i].to].fa=u;
     32             tree[edge[i].to].deep=tree[u].deep+1;
     33             dfs_weight(edge[i].to);
     34             tree[u].size+=tree[edge[i].to].size;
     35             if(tree[edge[i].to].size>tree[tree[u].son].size) tree[u].son=edge[i].to;
     36         }
     37     return;
     38 }
     39 void dfs_build(int u,int tp){
     40     tree[u].top=tp;
     41     tree[u].num=++tot;
     42     if(tree[u].son){
     43         dfs_build(tree[u].son,tp);
     44         for(int i=head[u];i;i=edge[i].next)
     45             if(edge[i].to!=tree[u].fa&&edge[i].to!=tree[u].son) dfs_build(edge[i].to,edge[i].to);
     46     }
     47     tree[u].end=tot;
     48     return;
     49 }
     50 void down(int pos,int ll,int mid,int rr){
     51     if(segtree[pos].mark){
     52         segtree[pos<<1].mark+=segtree[pos].mark;
     53         segtree[pos<<1|1].mark+=segtree[pos].mark;
     54         segtree[pos<<1].sum+=(mid-ll+1)*segtree[pos].mark;
     55         segtree[pos<<1].sum%=p;
     56         segtree[pos<<1|1].sum+=(rr-mid)*segtree[pos].mark;
     57         segtree[pos<<1|1].sum%=p;
     58         segtree[pos].mark=0;
     59         return;
     60     }
     61 }
     62 void update(int pl,int pr,int vl,int pos,int ll,int rr){
     63     if(pl<=ll&&pr>=rr){
     64         segtree[pos].mark+=vl;
     65         segtree[pos].sum+=(rr-ll+1)*vl;
     66         segtree[pos].sum%=p;
     67         return;
     68     }
     69     int mid=(ll+rr)>>1;
     70     down(pos,ll,mid,rr);
     71     if(pl<=mid) update(pl,pr,vl,pos<<1,ll,mid);
     72     if(pr>mid) update(pl,pr,vl,pos<<1|1,mid+1,rr);
     73     segtree[pos].sum=segtree[pos<<1].sum+segtree[pos<<1|1].sum;
     74     segtree[pos].sum%=p;
     75     return;
     76 }
     77 void add_val(int aa,int bb,int vl){
     78     int f1=tree[aa].top,f2=tree[bb].top;
     79     while(f1!=f2){
     80         if(tree[f1].deep<tree[f2].deep){
     81             update(tree[f2].num,tree[bb].num,vl,1,1,n);
     82             bb=tree[f2].fa;
     83             f2=tree[bb].top;
     84         }
     85         else{
     86             update(tree[f1].num,tree[aa].num,vl,1,1,n);
     87             aa=tree[f1].fa;
     88             f1=tree[aa].top;
     89         }
     90     }
     91     if(tree[aa].deep<tree[bb].deep) update(tree[aa].num,tree[bb].num,vl,1,1,n);
     92     else update(tree[bb].num,tree[aa].num,vl,1,1,n);
     93     return;
     94 }
     95 int ask(int pl,int pr,int pos,int ll,int rr){
     96     if(pl<=ll&&pr>=rr) return segtree[pos].sum;
     97     int mid=(ll+rr)>>1;
     98     down(pos,ll,mid,rr);
     99     int ans=0;
    100     if(pl<=mid){
    101         ans+=ask(pl,pr,pos<<1,ll,mid);
    102         ans%=p; 
    103     }
    104     if(pr>mid){
    105         ans+=ask(pl,pr,pos<<1|1,mid+1,rr);
    106         ans%=p;
    107     }
    108     return ans;
    109 }
    110 int ask_some(int aa,int bb){
    111     int f1=tree[aa].top,f2=tree[bb].top;
    112     int ans=0;
    113     while(f1!=f2){
    114         if(tree[f1].deep<tree[f2].deep){
    115             ans+=ask(tree[f2].num,tree[bb].num,1,1,n);
    116             ans%=p;
    117             bb=tree[f2].fa;
    118             f2=tree[bb].top;
    119         }
    120         else{
    121             ans+=ask(tree[f1].num,tree[aa].num,1,1,n);
    122             ans%=p;
    123             aa=tree[f1].fa;
    124             f1=tree[aa].top;
    125         }
    126     }
    127     if(tree[aa].deep<tree[bb].deep){
    128         ans+=ask(tree[aa].num,tree[bb].num,1,1,n);
    129         ans%=p;
    130     }
    131     else{
    132         ans+=ask(tree[bb].num,tree[aa].num,1,1,n);
    133         ans%=p;
    134     }
    135     return ans;
    136 }
    137 int main(){
    138     scanf("%d%d%d%d",&n,&m,&r,&p);
    139     for(int i=1;i<=n;i++) scanf("%d",&val[i]);
    140     int x,y;
    141     for(int i=1;i<n;i++){
    142         scanf("%d%d",&x,&y);
    143         add_edge(x,y);
    144         add_edge(y,x);
    145     }
    146     tree[r].deep=0;
    147     dfs_weight(r);
    148     dfs_build(r,r);; 
    149     for(int i=1;i<=n;i++) update(tree[i].num,tree[i].num,val[i],1,1,n);
    150     int od,a,b,c;
    151     for(int i=1;i<=m;i++){
    152         scanf("%d",&od);
    153         if(od==1){
    154             scanf("%d%d%d",&a,&b,&c);
    155             add_val(a,b,c);
    156             continue;
    157         }
    158         if(od==2){
    159             scanf("%d%d",&a,&b);
    160             printf("%d
    ",ask_some(a,b));
    161             continue;
    162         }
    163         if(od==3){
    164             scanf("%d%d",&a,&b);
    165             update(tree[a].num,tree[a].end,b,1,1,n);
    166             continue;
    167         }
    168         if(od==4){
    169             scanf("%d",&a);
    170             printf("%d
    ",ask(tree[a].num,tree[a].end,1,1,n));
    171             continue;
    172         }
    173     }
    174     return 0;
    175 }
  • 相关阅读:
    flash 自定义右键功能
    本地和VMware虚拟主机之间的网络访问
    java: org.luaj.vm2.LuaError:XXX module not found lua脚本初始化出错
    火狐 提示“此连接是不受信任的” 可能是因为开启了其它抓包代理软件导致的
    批量导入数据库
    引用Interop.SQLDMO.dll后的注意事项。
    c# Invoke和BeginInvoke 区别
    闭包的7种形式
    C#使用ICSharpCode.SharpZipLib压缩后进行web批量下载文件
    C# Socket编程笔记
  • 原文地址:https://www.cnblogs.com/zwube/p/6992527.html
Copyright © 2020-2023  润新知