zoukankan      html  css  js  c++  java
  • 洛谷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(重要的事情说三遍:记得取模)

    半夜强行自学树剖,明明半个月前还根本看不懂,这次居然神tm顿悟了。もう何も怖くない(じゃねいよ)

    大概就是把树边对应成线段树上的结点,一长串连着的边(重链)结点依次分布,散边(轻链)结点有规律分散,然后每次操作就和LCA倍增一样(并不)一路爬到根节点统计答案……

    然后一通乱搞。

      1 /*by SilverN*/
      2 #include<iostream>
      3 #include<algorithm>
      4 #include<cstring>
      5 #include<cstdio>
      6 #include<cmath>
      7 #define LL long long
      8 using namespace std;
      9 const int mxn=100010;
     10 int read(){
     11     int x=0,f=1;char ch=getchar();
     12     while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
     13     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
     14     return x*f;
     15 }
     16 //读入优化 
     17 struct edge{int v,nxt;}e[mxn<<1];
     18 int hd[mxn],mct=0;
     19 void add_edge(int u,int v){e[++mct].v=v;e[mct].nxt=hd[u];hd[u]=mct;}
     20 //邻接表 
     21 struct node{
     22     int fa,son;
     23     int size,dep,top;
     24     int w,e;
     25 }tr[mxn];
     26 //树剖结点 
     27 struct segtree{
     28     LL smm,mk;
     29 }st[mxn<<2];
     30 int sz=0;
     31 //线段树 
     32 int n,M,rt,mod;
     33 int w[mxn];//初始值 
     34 //
     35 void DFS1(int u){
     36     tr[u].size=1;tr[u].son=0;
     37     for(int i=hd[u];i;i=e[i].nxt){
     38         int v=e[i].v;
     39         if(v==tr[u].fa)continue;
     40         tr[v].fa=u;
     41         tr[v].dep=tr[u].dep+1;
     42         DFS1(v);
     43         tr[u].size+=tr[v].size;
     44         if(tr[v].size>tr[tr[u].son].size)
     45             tr[u].son=v;
     46     }
     47     return;
     48 }
     49 void DFS2(int u,int top){//当前点,当前链的顶点 
     50     tr[u].top=top;
     51     tr[u].w=++sz;//把树边挂上线段树 
     52     if(tr[u].son){
     53         DFS2(tr[u].son,top);//扩展搭建重链 
     54         for(int i=hd[u];i;i=e[i].nxt){
     55             int v=e[i].v;
     56             if(v!=tr[u].fa && v!=tr[u].son)
     57                 DFS2(v,v);//搭建轻链 
     58         }
     59     }
     60     tr[u].e=sz;//当前点对应的线段树结尾
     61     return; 
     62 }
     63 void update(int L,int R,LL w,int l,int r,int k){//区间加值
     64      if(L<=l && r<=R){
     65          st[k].mk+=w;
     66          st[k].smm+=(r-l+1)*w;
     67          st[k].smm%=mod;
     68          return;
     69     }
     70     int mid=(l+r)>>1;
     71     if(st[k].mk){
     72         st[k<<1].mk+=st[k].mk;
     73         st[k<<1].smm+=st[k].mk*(mid-l+1);
     74         st[k<<1].smm%=mod;
     75         st[k<<1|1].mk+=st[k].mk;
     76         st[k<<1|1].smm+=st[k].mk*(r-mid);
     77         st[k<<1|1].smm%=mod;
     78         st[k].mk=0;
     79     }
     80     if(L<=mid)update(L,R,w,l,mid,k<<1);
     81     if(R>mid)update(L,R,w,mid+1,r,k<<1|1);
     82     st[k].smm=(st[k<<1].smm+st[k<<1|1].smm)%mod;
     83     return;
     84 }
     85 int query(int L,int R,int l,int r,int k){
     86     if(L<=l && r<=R)return st[k].smm;
     87     int mid=(l+r)>>1;
     88     if(st[k].mk){
     89         st[k<<1].mk+=st[k].mk;
     90         st[k<<1].smm+=st[k].mk*(mid-l+1);
     91         st[k<<1].smm%=mod;
     92         st[k<<1|1].mk+=st[k].mk;
     93         st[k<<1|1].smm+=st[k].mk*(r-mid);
     94         st[k<<1|1].smm%=mod;
     95         st[k].mk=0;
     96     }
     97     LL res=0;
     98     if(L<=mid)res=(res+query(L,R,l,mid,k<<1))%mod;
     99     if(R>mid)res=(res+query(L,R,mid+1,r,k<<1|1))%mod;
    100     return res%mod;
    101 }
    102 int find(int x,int y){
    103     int f1=tr[x].top,f2=tr[y].top;
    104     int ans=0;
    105     while(f1!=f2){
    106         if(tr[f1].dep<tr[f2].dep){
    107             ans+=query(tr[f2].w,tr[y].w,1,n,1);
    108             y=tr[f2].fa;
    109             f2=tr[y].top;
    110         }
    111         else{
    112             ans+=query(tr[f1].w,tr[x].w,1,n,1);
    113             x=tr[f1].fa;
    114             f1=tr[x].top;
    115         }
    116         ans%=mod;
    117     }
    118     if(tr[x].dep<tr[y].dep)return ans+query(tr[x].w,tr[y].w,1,n,1);
    119     return ans+query(tr[y].w,tr[x].w,1,n,1);
    120 }
    121 void add(int x,int y,int k){//x到y的路径加k 
    122     int f1=tr[x].top,f2=tr[y].top;
    123     while(f1!=f2){
    124         if(tr[f1].dep<tr[f2].dep){
    125             update(tr[f2].w,tr[y].w,k,1,n,1);
    126             y=tr[f2].fa;
    127             f2=tr[y].top;
    128         }
    129         else{
    130             update(tr[f1].w,tr[x].w,k,1,n,1);
    131             x=tr[f1].fa;
    132             f1=tr[x].top;
    133         }
    134     }
    135     if(tr[x].dep<tr[y].dep) update(tr[x].w,tr[y].w,k,1,n,1);
    136     else update(tr[y].w,tr[x].w,k,1,n,1);
    137     return;
    138 }
    139 //
    140 int main(){
    141     n=read();M=read();rt=read();mod=read();
    142     int i,j;
    143     for(i=1;i<=n;i++){w[i]=read();}
    144     int x,y;
    145     for(i=1;i<n;i++){
    146         x=read();y=read();
    147         add_edge(x,y);
    148         add_edge(y,x);
    149     }
    150     sz=tr[0].size=tr[rt].dep=0;
    151     //
    152     DFS1(rt);
    153     DFS2(rt,rt);
    154     for(i=1;i<=n;i++)update(tr[i].w,tr[i].w,w[i],1,n,1);
    155     int op;
    156     for(i=1;i<=M;i++){
    157         op=read();x=read();
    158         switch(op){
    159             case 4:{
    160                 printf("%d
    ",query(tr[x].w,tr[x].e,1,n,1)%mod);
    161                 break;
    162             }
    163             case 3:{
    164                 y=read();
    165                 update(tr[x].w,tr[x].e,y,1,n,1);
    166                 break;
    167             }
    168             case 2:{
    169                 y=read();
    170                 printf("%d
    ",find(x,y)%mod);
    171                 break;
    172             }
    173             case 1:{
    174                 y=read();j=read();
    175                 add(x,y,j);
    176                 break;
    177             }
    178         }
    179     }
    180     return 0;
    181 }
  • 相关阅读:
    将数据绑定通过图表显现
    d3.js初识
    Josn
    d3-tip.js
    Java知识点总结
    Javascript的学习
    Java的多线程学习
    day11
    day10
    day09
  • 原文地址:https://www.cnblogs.com/SilverNebula/p/6025052.html
Copyright © 2011-2022 走看看