• 树链剖分模版


    注意事项:

    1、把握好“树节点”与“RMQ节点”的关系,

    即build时,dat[k]=a[pre[L]];query时,调用需加上tree[x],tree[y]

    有时候又不需要加tree[x],比如处理子树。

    2、线段树确保正确,数组开4倍

    3、树链剖分的循环中,必须先处理链顶深度较大的,如果直接处理节点深度大的,可能出现这种情况:

    如图,如果是按照dep[x]>dep[y],那么x直接上去,求的就不是最短路径了

    反之,如果按照dep[f2]>dep[f1],则没有问题


      1 #include<cstdio>
      2 #include<cstdlib>
      3 #include<algorithm>
      4 #include<cstring>
      5 #define MAXN 100005
      6 #define ll long long
      7 using namespace std;
      8 int first[MAXN],Next[MAXN*2],to[MAXN*2],cnt;
      9 //double edge
     10 ll Val[MAXN];
     11 int dep[MAXN],size[MAXN],fa[MAXN],son[MAXN];
     12 int top[MAXN],tree[MAXN],pre[MAXN],num;
     13 int V,root;
     14 ll MOD;
     15 //tree node -> tree
     16 //pre tree-> node
     17 void Add(int x,int y){
     18     Next[++cnt]=first[x];first[x]=cnt;to[cnt]=y;
     19     Next[++cnt]=first[y];first[y]=cnt;to[cnt]=x;
     20 }
     21 void dfs1(int x){
     22     size[x]=1;
     23     for(int e=first[x];e;e=Next[e]){
     24         int y=to[e];
     25         if(fa[x]==y) continue;
     26         fa[y]=x;
     27         dep[y]=dep[x]+1;
     28         dfs1(y);
     29         size[x]+=size[y];
     30         if(size[y]>size[son[x]]){
     31             son[x]=y;
     32         }
     33     }
     34 }
     35 void dfs2(int x,int t){
     36     top[x]=t;
     37     tree[x]=(++num);
     38     pre[num]=x;
     39     if(!son[x]){
     40         return ;
     41     }
     42     dfs2(son[x],t);
     43     for(int e=first[x];e;e=Next[e]){
     44         int y=to[e];
     45         if(y==fa[x]||y==son[x]) continue;
     46         dfs2(y,y);
     47     }
     48 }
     49 ll dat[MAXN*4];
     50 ll tag[MAXN*4];
     51 //kai si bei
     52 void build(int k,int L,int R){
     53     if(L+1==R){
     54         dat[k]=Val[pre[L]];
     55         return ;
     56         //remember to return here
     57     }
     58     build(k<<1,L,(L+R)>>1);
     59     build(k<<1|1,(L+R)>>1,R);
     60     dat[k]=(dat[k<<1]+dat[k<<1|1])%MOD;
     61 }
     62 void pushdown(int k,int L,int R){
     63     int lc=(k<<1),rc=(k<<1|1);
     64     int mid=((L+R)>>1);
     65     int ls=mid-L,rs=R-mid;
     66     dat[lc]=(dat[lc]+ls*tag[k])%MOD;
     67     dat[rc]=(dat[rc]+rs*tag[k])%MOD;
     68     tag[lc]=(tag[lc]+tag[k])%MOD;
     69     tag[rc]=(tag[rc]+tag[k])%MOD;
     70     tag[k]=0;
     71 }
     72 ll RMQ_query(int a,int b,int k,int L,int R){
     73     if(b<=L||R<=a){
     74         return 0;
     75     }    
     76     else if(a<=L&&R<=b){
     77         return dat[k];
     78     }
     79     else{
     80         if(tag[k]){
     81             pushdown(k,L,R);
     82         }
     83         ll lc=RMQ_query(a,b,k<<1,L,(L+R)>>1);
     84         ll rc=RMQ_query(a,b,k<<1|1,(L+R)>>1,R);
     85         return (lc+rc)%MOD;
     86     }
     87 }
     88 void RMQ_update(int a,int b,int k,int L,int R,ll t){
     89     if(b<=L||R<=a){
     90         return;
     91     }
     92     else if(a<=L&&R<=b){
     93         dat[k]=(dat[k]+(R-L)*t)%MOD;
     94         tag[k]=(tag[k]+t)%MOD;
     95     }
     96     else{
     97         if(tag[k]){
     98             pushdown(k,L,R);
     99         }
    100         RMQ_update(a,b,k<<1,L,(L+R)>>1,t);
    101         RMQ_update(a,b,k<<1|1,(L+R)>>1,R,t);
    102         dat[k]=(dat[k<<1]+dat[k<<1|1])%MOD;
    103     }
    104 }
    105 ll Tree_query(int x,int y){
    106     ll ret=0;
    107     int f1=top[x],f2=top[y];
    108     while(f1!=f2){
    109         if(dep[f1]<dep[f2]){
    110             swap(x,y);swap(f1,f2);
    111         }
    112         ll t=RMQ_query(tree[f1],tree[x]+1,1,1,V+1);
    113         ret=(ret+t)%MOD;
    114         x=fa[f1];f1=top[x];
    115     }
    116     if(dep[x]<dep[y]){
    117         swap(x,y);
    118     }
    119     ll t=RMQ_query(tree[y],tree[x]+1,1,1,V+1);
    120     ret=(ret+t)%MOD;
    121     return ret;
    122 }
    123 void Tree_update(int x,int y,ll t){
    124     int f1=top[x],f2=top[y];
    125     while(f1!=f2){
    126         if(dep[f1]<dep[f2]){
    127             swap(x,y);swap(f1,f2);
    128         }
    129         RMQ_update(tree[f1],tree[x]+1,1,1,V+1,t);
    130         x=fa[f1];f1=top[x];
    131     }
    132     if(dep[x]<dep[y]){
    133         swap(x,y);
    134     }
    135     RMQ_update(tree[y],tree[x]+1,1,1,V+1,t);
    136 }
    137 void solve1(){
    138     int x,y; ll t;
    139     scanf("%d%d%lld",&x,&y,&t);
    140     Tree_update(x,y,t);
    141 }
    142 void solve2(){
    143     int x,y;
    144     scanf("%d%d",&x,&y);
    145     ll ans=Tree_query(x,y);
    146     printf("%lld
    ",ans);
    147 }
    148 void solve3(){
    149     int x;ll t;
    150     scanf("%d%lld",&x,&t);
    151     int y=tree[x]+size[x]-1;
    152     x=tree[x];
    153     RMQ_update(x,y+1,1,1,V+1,t);
    154 }
    155 void solve4(){
    156     int x;
    157     scanf("%d",&x);
    158     int y=tree[x]+size[x]-1;
    159     x=tree[x];
    160     ll ans=RMQ_query(x,y+1,1,1,V+1);
    161     printf("%lld
    ",ans);
    162 }
    163 int main()
    164 {
    165  //   freopen("data.in","r",stdin);
    166     int T;
    167     scanf("%d%d%d%d",&V,&T,&root,&MOD);
    168     for(int i=1;i<=V;i++){
    169         scanf("%lld",&Val[i]);
    170     }
    171     for(int i=1;i<V;i++){
    172         int x,y;
    173         scanf("%d%d",&x,&y);
    174         Add(x,y);
    175     }
    176     dfs1(root);
    177     dfs2(root,root);
    178     build(1,1,V+1);
    179     for(int i=1;i<=T;i++){
    180         int p;
    181         scanf("%d",&p);
    182         if(1==p){
    183             solve1();
    184         }
    185         else if(2==p){
    186             solve2();
    187         }
    188         else if(3==p){
    189             solve3();
    190         }
    191         else{
    192             solve4();
    193         }
    194     }
    195     return 0;
    196 }
    View Code

    模版链接:https://www.luogu.org/problem/show?pid=3384

  • 相关阅读:
    汇编笔记
    PHP笔记——SOAP
    Eclipse 插件资源地址记录
    使用SetWindowLong修改窗口样式
    C++ builder 剪贴板Clipboard使用
    c++ builder 实现右键选择节点实现方式
    c++ builder 使listview获得焦点并选择第一个节点
    c++ builder 2009 启用codeguard 检测内存泄漏
    c++ builder 2009如何生成独立运行exe
    WPF编程学习——样式
  • 原文地址:https://www.cnblogs.com/w-h-h/p/7613380.html
Copyright © 2020-2023  润新知