• 洛谷 P3384 【模板】树链剖分 如题


    P3384 【模板】树链剖分

    • 时空限制1s / 128MB

    题目描述

    如题,已知一棵包含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(重要的事情说三遍:记得取模)

    -------------------------------------------------------------------------------------------------------------

    树链剖分就是把在原树上的操作转化为在线段树上操作

    对于操作一、三,我们把它变成区间加;

    对于操作二、四,变成区间求和。

    特别的,对于操作三、四

    因为原树上的点的映射pos(其实就是给原树结点重新编号)有着连续性:

           一个结点的父节点一定小于这个结点,且是连续的

           所以一颗子树中所有的点都比根节点大,且是连续的

     所以可以放到线段树上操作

    比如映射点pos[x]的子树,在线段树上的区间为pos[x]到pos[x]+size[x]-1    //size[x]表示以x为根节点的子树拥有的结点总数

     

    感觉比   这题   要难?

    存板子:

      1 #include<stdio.h>
      2 #include<string.h>
      3 #include<iostream>
      4 #define maxn 233333
      5 using namespace std;
      6 struct node{int to,next;};
      7 struct rode{int l,r,sum,tag;};
      8 node e[maxn<<1];
      9 rode tr[maxn<<2];
     10 int read();
     11 int n,m,r,p,pre[maxn],cnt,v[maxn],fa[maxn],dep[maxn],size[maxn],poi,pos[maxn],bl[maxn];
     12 int solvelsum(int,int);
     13 void ladd(int,int,int);
     14 void add(int,int,int,int);
     15 int querysum(int,int,int);
     16 void pushdown(int);
     17 void pushup(int);
     18 void change(int,int,int);
     19 void build(int,int,int);
     20 void dfs1(int);
     21 void dfs2(int,int);
     22 void ins(int,int);
     23 int main(){
     24     n=read();m=read();r=read();p=read();
     25     for(int i=1;i<=n;i++) v[i]=read();
     26     cnt=0;poi=0;
     27     for(int i=1;i<n;i++){
     28         int x=read(),y=read();
     29         ins(x,y);
     30     }
     31     fa[r]=r;dep[r]=1;
     32     dfs1(r);
     33     dfs2(r,r);
     34     build(1,n,1);
     35     for(int i=1;i<=n;i++) change(pos[i],v[i],1);
     36     for(int i=1;i<=m;i++){
     37         int o=read();
     38         if(o==1){
     39             int x=read(),y=read(),z=read();
     40             ladd(x,y,z);
     41         }
     42         else if(o==2){
     43             int x=read(),y=read(); 
     44             printf("%d
    ",solvelsum(x,y));
     45         }
     46         else if(o==3){
     47             int x=read(),y=read();
     48             add(pos[x],pos[x]+size[x]-1,y,1);
     49         }
     50         else{
     51             int x=read();
     52             printf("%d
    ",querysum(pos[x],pos[x]+size[x]-1,1));
     53         }
     54     }
     55     return 0;
     56 }
     57 #define lson ro<<1
     58 #define rson ro<<1|1
     59 int solvelsum(int x,int y){
     60     int sum=0;
     61     while(bl[x]!=bl[y]){
     62         if(dep[bl[x]]<dep[bl[y]]) swap(x,y);
     63         sum=(sum+querysum(pos[bl[x]],pos[x],1))%p;
     64         x=fa[bl[x]];
     65     }
     66     if(pos[x]>pos[y]) swap(x,y);
     67     sum=(sum+querysum(pos[x],pos[y],1))%p;
     68     return sum;
     69 }
     70 void ladd(int x,int y,int k){
     71     while(bl[x]!=bl[y]){
     72         if(dep[bl[x]]<dep[bl[y]]) swap(x,y);
     73         add(pos[bl[x]],pos[x],k,1);
     74         x=fa[bl[x]];
     75     }
     76     if(pos[x]>pos[y]) swap(x,y);
     77     add(pos[x],pos[y],k,1);
     78 }
     79 void add(int l,int r,int k,int ro){
     80     if(l<=tr[ro].l&&tr[ro].r<=r){
     81         tr[ro].sum=(tr[ro].sum+(tr[ro].r-tr[ro].l+1)*k)%p;
     82         tr[ro].tag=(tr[ro].tag+k)%p;
     83         return;
     84     }
     85     if(tr[ro].tag) pushdown(ro);
     86     int mid=(tr[ro].l+tr[ro].r)>>1;
     87     if(l<=mid) add(l,r,k,lson);
     88     if(r>mid)  add(l,r,k,rson);
     89     pushup(ro);
     90 }
     91 int querysum(int l,int r,int ro){
     92     if(l<=tr[ro].l&&tr[ro].r<=r) return tr[ro].sum;
     93     if(tr[ro].tag) pushdown(ro);
     94     int mid=(tr[ro].l+tr[ro].r)>>1;
     95     if(l<=mid&&mid<r) return (querysum(l,r,lson)+querysum(l,r,rson))%p;
     96     if(l<=mid) return querysum(l,r,lson);
     97     if(r>mid) return querysum(l,r,rson);
     98 }
     99 void pushdown(int ro){
    100     int k=tr[ro].tag;tr[ro].tag=0;
    101     tr[lson].tag=(tr[lson].tag+k)%p;
    102     tr[rson].tag=(tr[rson].tag+k)%p;
    103     tr[lson].sum=(tr[lson].sum+(tr[lson].r-tr[lson].l+1)*k)%p;
    104     tr[rson].sum=(tr[rson].sum+(tr[rson].r-tr[rson].l+1)*k)%p;
    105 }
    106 void pushup(int ro){
    107     tr[ro].sum=(tr[lson].sum+tr[rson].sum)%p;
    108 }
    109 void change(int x,int k,int ro){
    110     if(tr[ro].l==tr[ro].r){
    111         tr[ro].sum=k%p;
    112         return;
    113     }
    114     int mid=(tr[ro].l+tr[ro].r)>>1;
    115     if(x<=mid) change(x,k,lson);
    116     else change(x,k,rson);
    117     pushup(ro);
    118 }
    119 void build(int l,int r,int ro){
    120     tr[ro].l=l;tr[ro].r=r;
    121     if(l==r) return;
    122     int mid=(l+r)>>1;
    123     build(l,mid,lson);
    124     build(mid+1,r,rson);
    125 }
    126 void dfs2(int x,int chain){
    127     int k=0;
    128     pos[x]=++poi;
    129     bl[x]=chain;
    130     for(int i=pre[x];i;i=e[i].next){
    131         int to=e[i].to;
    132         if(dep[to]>dep[x]&&size[to]>size[k]) k=to;
    133     }
    134     if(k==0) return;
    135     dfs2(k,chain);
    136     for(int i=pre[x];i;i=e[i].next){
    137         int to=e[i].to;
    138         if(dep[to]>dep[x]&&k!=to) dfs2(to,to);
    139     }
    140 }
    141 void dfs1(int x){
    142     size[x]=1;
    143     for(int i=pre[x];i;i=e[i].next){
    144         int to=e[i].to;
    145         if(fa[x]!=to){
    146             fa[to]=x;
    147             dep[to]=dep[x]+1;
    148             dfs1(to);
    149             size[x]+=size[to];
    150         }
    151     }
    152 }
    153 void ins(int x,int y){
    154     e[++cnt].to=y;e[cnt].next=pre[x];pre[x]=cnt;
    155     e[++cnt].to=x;e[cnt].next=pre[y];pre[y]=cnt;
    156 }
    157 int read(){
    158     int ans=0,f=1;char c=getchar();
    159     while('0'>c||c>'9'){if(c=='-')f=-1;c=getchar();}
    160     while('0'<=c&&c<='9')ans=ans*10+c-48,c=getchar();return ans*f;
    161 }
    树链剖分
  • 相关阅读:
    .net core 大型事务的处理办法
    .net Core把一个list集合里面的所有字段的数值汇总
    C#使用模板导出Excel
    JQuery滚动分页查询功能
    返回一个条件表达式树的拓展方法
    C++类的大小
    基数排序-八大排序汇总(8)
    归并排序-八大排序汇总(7)
    快速排序(交换排序)-八大排序汇总(6)
    希尔排序(插入排序)-八大排序汇总(5)
  • 原文地址:https://www.cnblogs.com/lpl-bys/p/7815223.html
Copyright © 2020-2023  润新知