zoukankan      html  css  js  c++  java
  • 题解报告——【模板】树链剖分

    题目描述

    如题,已知一棵包含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 leq 10, M leq 10N10,M10

    对于70%的数据: N leq {10}^3, M leq {10}^3N103,M103

    对于100%的数据: N leq {10}^5, M leq {10}^5N105,M105

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

    样例说明:

    树的结构如下:

    各个操作如下:

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


    【思路分析】

    这道题说是树链剖分模板,其实还要套一个线段树就OK了

    我们发现,这个树链剖分与求LCA的唯一区别在于需要维护链上树上的信息,那么我们怎么实现维护链上树上的信息呢?

    这里我们就要好好利用我们剖分树链时的遍历顺序!!!

    对于求链上的信息时,因为我们第二次dfs优先遍历的是父节点的最大子节点,也就是先遍历重链,所以我们每条重链上的遍历的编号是连续的,所以我们可以用线段树维护这段区间的信息。

    对于求子树的信息时,因为我们每次是先遍历完了一个父节点的所有子节点后在遍历另一个父节点,导致我们每棵子树也都是编号连续的,同理也可以用线段树维护。

     1 int ask1(int v,int lx,int rx)
     2 {
     3     pushdown(v);
     4     if(t[v].l==lx&&t[v].r==rx)
     5         return t[v].key;
     6     int ls=t[v].son[0],rs=t[v].son[1],mid=(t[v].l+t[v].r)/2;
     7     if(lx>mid) return ask1(rs,lx,rx);
     8     else
     9     if(rx<=mid) return ask1(ls,lx,rx);
    10     else 
    11     return (ask1(ls,lx,mid)+ask1(rs,mid+1,rx))%mod;
    12 }
    13 int tree_sum(int x,int y)
    14 {
    15     int ans=0;
    16     while(top[x]!=top[y])
    17     {
    18         if(dep[top[x]]<dep[top[y]]) {int t=x;x=y;y=t;}
    19         ans=(ans+ask1(1,idx[top[x]],idx[x]))%mod;
    20         x=fa[top[x]];
    21     }
    22     if(dep[x]>dep[y]) {int t=x;x=y;y=t;}
    23     ans=(ans+ask1(1,idx[x],idx[y]))%mod;
    24     return ans;
    25 }

    那么对于链上、子树修改也同理,每次去当前点到链顶进行维护


    【代码实现】

      1 #include<cstdio>
      2 #include<vector>
      3 using namespace std;
      4 const int maxn=100000;
      5 int top[maxn+5],fa[maxn+5],son[maxn+5],siz[maxn+5],dep[maxn+5],head[maxn+5],ww[maxn+5],ord[maxn+5],idx[maxn+5];
      6 struct sd{
      7     int to,next;
      8 }edge[2*maxn+5];
      9 struct sd2{
     10     int l,r,son[2],key,add;
     11 }t[maxn*2+5];
     12 int cnt,n,m,root,mod;
     13 void add_edge(int a,int b)
     14 {
     15     edge[++cnt].to=b;
     16     edge[cnt].next=head[a];
     17     head[a]=cnt;
     18 }
     19 int dfs(int now,int ff,int deep)
     20 {
     21     fa[now]=ff,dep[now]=deep,siz[now]=1;
     22     int ms=-1,maxx=-1;
     23     for(int i=head[now];i!=0;i=edge[i].next)
     24     {
     25         if(edge[i].to!=ff)
     26         {
     27             int gg=dfs(edge[i].to,now,deep+1);
     28             if(maxx<gg)
     29             { maxx=gg,ms=edge[i].to; }
     30             siz[now]+=gg;
     31         }
     32     }
     33     if(ms==-1) son[now]=now;
     34     else son[now]=ms;
     35     return siz[now];
     36 }
     37 void dfs2(int now,int tt)
     38 {
     39     cnt++,ord[cnt]=now,idx[now]=cnt,top[now]=tt;
     40     if(son[now]==now) return;
     41     dfs2(son[now],tt);
     42     for(int i=head[now];i!=0;i=edge[i].next)
     43     {
     44         if(edge[i].to!=fa[now]&&edge[i].to!=son[now])
     45             dfs2(edge[i].to,edge[i].to);
     46     }
     47 }
     48 void build(int &v,int lx,int rx)
     49 {
     50     cnt++,v=cnt,t[v].l=lx,t[v].r=rx;
     51     if(lx==rx)
     52     { t[v].key=ww[ord[lx]];return; }
     53     int mid=(lx+rx)/2;
     54     build(t[v].son[0],lx,mid);
     55     build(t[v].son[1],mid+1,rx);
     56     t[v].key=t[t[v].son[0]].key+t[t[v].son[1]].key;
     57 }
     58 void pushdown(int v)
     59 {
     60     if(t[v].l==t[v].r) return;
     61     if(t[v].add)
     62     {
     63         int ls=t[v].son[0],rs=t[v].son[1];
     64         t[ls].key=(t[ls].key+(t[ls].r-t[ls].l+1)*t[v].add)%mod;
     65         t[rs].key=(t[rs].key+(t[rs].r-t[rs].l+1)*t[v].add)%mod;
     66         t[ls].add=(t[ls].add+t[v].add)%mod,t[rs].add=(t[rs].add+t[v].add)%mod;
     67         t[v].add=0;
     68     } 
     69 }
     70 void add1(int v,int lx,int rx,int z)
     71 {
     72     pushdown(v);
     73     if(t[v].l==lx&&t[v].r==rx)
     74     {
     75         t[v].add=(t[v].add+z)%mod;
     76         t[v].key=(z*(t[v].r-t[v].l+1)+t[v].key)%mod;
     77         return;
     78     }
     79     int ls=t[v].son[0],rs=t[v].son[1],mid=(t[v].l+t[v].r)/2;
     80     if(lx>mid) add1(rs,lx,rx,z);
     81     else
     82     if(rx<=mid) add1(ls,lx,rx,z);
     83     else 
     84     {
     85         add1(ls,lx,mid,z);
     86         add1(rs,mid+1,rx,z);
     87     }
     88     t[v].key=(t[ls].key+t[rs].key)%mod;
     89 }
     90 int ask1(int v,int lx,int rx)
     91 {
     92     pushdown(v);
     93     if(t[v].l==lx&&t[v].r==rx)
     94         return t[v].key;
     95     int ls=t[v].son[0],rs=t[v].son[1],mid=(t[v].l+t[v].r)/2;
     96     if(lx>mid) return ask1(rs,lx,rx);
     97     else
     98     if(rx<=mid) return ask1(ls,lx,rx);
     99     else 
    100     return (ask1(ls,lx,mid)+ask1(rs,mid+1,rx))%mod;
    101 }
    102 void tree_add(int x,int y,int z)
    103 {
    104     while(top[x]!=top[y])
    105     {
    106         if(dep[top[x]]<dep[top[y]]) {int t=x;x=y;y=t;}
    107         add1(1,idx[top[x]],idx[x],z);
    108         x=fa[top[x]];
    109     }
    110     if(dep[x]>dep[y]) {int t=x;x=y;y=t;}
    111     add1(1,idx[x],idx[y],z);
    112 }
    113 int tree_sum(int x,int y)
    114 {
    115     int ans=0;
    116     while(top[x]!=top[y])
    117     {
    118         if(dep[top[x]]<dep[top[y]]) {int t=x;x=y;y=t;}
    119         ans=(ans+ask1(1,idx[top[x]],idx[x]))%mod;
    120         x=fa[top[x]];
    121     }
    122     if(dep[x]>dep[y]) {int t=x;x=y;y=t;}
    123     ans=(ans+ask1(1,idx[x],idx[y]))%mod;
    124     return ans;
    125 }
    126 int main()
    127 {
    128     scanf("%d%d%d%d",&n,&m,&root,&mod);
    129     for(int i=1;i<=n;i++) scanf("%d",&ww[i]);
    130     for(int i=1;i<n;i++)
    131     {
    132         int a,b;
    133         scanf("%d%d",&a,&b);
    134         add_edge(a,b);add_edge(b,a);
    135     }
    136     dfs(root,0,1);
    137     cnt=0;
    138     dfs2(root,root);
    139     int rr;cnt=0;
    140     build(rr,1,n);
    141     for(int i=1;i<=m;i++)
    142     {
    143         int orz;
    144         scanf("%d",&orz);
    145         if(orz==1)
    146         {
    147             int x,y,z;
    148             scanf("%d%d%d",&x,&y,&z);
    149             tree_add(x,y,z);
    150         }
    151         if(orz==2)
    152         {
    153             int x,y;
    154             scanf("%d%d",&x,&y);
    155             printf("%d
    ",tree_sum(x,y));
    156         }
    157         if(orz==3)
    158         {
    159             int x,z;
    160             scanf("%d%d",&x,&z);
    161             add1(1,idx[x],idx[x]+siz[x]-1,z);
    162         }
    163         if(orz==4)
    164         {
    165             int x;
    166             scanf("%d",&x);
    167             printf("%d
    ",ask1(1,idx[x],idx[x]+siz[x]-1));
    168         }
    169     }
    170     return 0;
    171 }
  • 相关阅读:
    使用Azure Rest API获得Access Token介绍
    Azure Service Fabric应用程序日志记录与展现
    Azure Web App创建Python应用
    AzureWeb App如何做私有仓储的部署
    Python web在IIS上发布方法和原理
    [转载]DriverStore文件夹特别大,能删除吗?
    Azure Web APP中Local Git 如何部署分支
    Azure Web 应用如何修改 IIS 配置
    文件上传绕过
    windows下通过配置服务器安全策略指定IP地址远程访问服务器的设置方法
  • 原文地址:https://www.cnblogs.com/genius777/p/8719311.html
Copyright © 2011-2022 走看看