1. 程式人生 > >樹鏈剖分模板(洛谷P3384)

樹鏈剖分模板(洛谷P3384)

直接 void treenode mes pre getc problem bits dep

洛谷P3384

#include <bits/stdc++.h>
#define DBG(x) cerr << #x << " = " << x << endl;
const int maxn = 1e5+5;
using namespace std;

inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch < ‘0‘ || ch > ‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
    while(ch >= ‘0‘ && ch <= ‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
    return x*f;
}

int n,m,rot,mod;
int w[maxn],wt[maxn];///剖分前後的點權,不要抄錯QAQ
int head[maxn],tot;
int cnt,dep[maxn],siz[maxn],fa[maxn],son[maxn],id[maxn],top[maxn];///son[i]表示i的重兒子,top[i]表示i所在鏈的頂點
int ans;

struct treenode{
    int l,r,val,add;
}tree[maxn<<2];

struct edgenode{
    int to,next;
}edge[maxn<<1];

void addedge(int u,int v){
    edge[tot].to=v;
    edge[tot].next=head[u];
    head[u]=tot++;
}

void push_up(int x){
    tree[x].val=tree[x<<1].val+tree[x<<1|1].val;
    tree[x].val%=mod;
}

void push_down(int x,int len){
    if(tree[x].add){
        tree[x<<1].add+=tree[x].add;
        tree[x<<1|1].add+=tree[x].add;
        tree[x<<1].val+=(len-(len>>1))*tree[x].add;
        tree[x<<1|1].val+=(len>>1)*tree[x].add;
        tree[x<<1].val%=mod;
        tree[x<<1|1].val%=mod;
        tree[x].add=0;
    }
}

void build(int i,int l,int r){
    tree[i].l=l;
    tree[i].r=r;
    tree[i].add=0;
    if(l == r){
        tree[i].val=wt[l];
        tree[i].val%=mod;
        return;
    }
    int mid=(l+r)>>1;
    build(i<<1,l,mid);
    build(i<<1|1,mid+1,r);
    push_up(i);
}

void update(int i,int l,int r,int L,int R,int c){
    if(l >= L && r <= R){
        tree[i].val+=(r-l+1)*c;
        tree[i].add+=c;
        return;
    }
    push_down(i,r-l+1);
    int mid=(l+r)>>1;
    if(L <= mid)update(i<<1,l,mid,L,R,c);
    if(R > mid)update(i<<1|1,mid+1,r,L,R,c);
    push_up(i);
}

void query(int i,int l,int r,int L,int R){
    if(l >= L && r <= R){
        ans+=tree[i].val;
        ans%=mod;
        return;
    }
    push_down(i,r-l+1);
    int mid=(l+r)>>1;
    if(L <= mid)query(i<<1,l,mid,L,R);
    if(R > mid)query(i<<1|1,mid+1,r,L,R);
}

void dfs1(int x,int pre,int deep){///確定各節點層次,子樹大小,父節點編號,重兒子編號
    dep[x]=deep;
    fa[x]=pre;
    siz[x]=1;
    int maxson=-1;
    for(int i=head[x];i != -1;i=edge[i].next){
        int v=edge[i].to;
        if(v != pre){
            dfs1(v,x,deep+1);
            siz[x]+=siz[v];
            if(siz[v] > maxson){maxson=siz[v];son[x]=v;}
        }
    }
}

void dfs2(int x,int topf){///確定各鏈的信息,包括鏈的頂點以及鏈上點的新編號
    id[x]=++cnt;
    wt[id[x]]=w[x];
    top[x]=topf;
    if(!son[x])return;
    dfs2(son[x],topf);
    for(int i=head[x];i != -1;i=edge[i].next){
        int v=edge[i].to;
        if(v == fa[x] || v == son[x])continue;
        dfs2(v,v);
    }
}

void spilt(){
    dfs1(rot,0,1);
    dfs2(rot,rot);
    build(1,1,n);
}
/*查詢兩點路徑上的點權和*/
int qRange(int x,int y){///讓深度深的點往上跳到頂點並更新對答案的貢獻
    int res=0;          ///之後更新到舊鏈頂上的鏈,重復過程直到兩點在同一條鏈上
    while(top[x] != top[y]){
        if(dep[top[x]] < dep[top[y]])swap(x,y);
        ans=0;
        query(1,1,n,id[top[x]],id[x]);
        res+=ans;
        res%=mod;
        x=fa[top[x]];
    }
    if(dep[x] > dep[y])swap(x,y);
    ans=0;
    query(1,1,n,id[x],id[y]);
    res+=ans;
    return res%mod;
}
/*更新同查詢*/
void updRange(int x,int y,int c){
    c%=mod;
    while(top[x] != top[y]){
        if(dep[top[x]] < dep[top[y]])swap(x,y);
        update(1,1,n,id[top[x]],id[x],c);
        x=fa[top[x]];
    }
    if(dep[x] > dep[y])swap(x,y);
    update(1,1,n,id[x],id[y],c);
}
/*查詢子樹點權和*/
int qSon(int x){///由於新編號連續,直接查詢樹根到樹根+樹的大小,這段區間對應整個子樹
    ans=0;
    query(1,1,n,id[x],id[x]+siz[x]-1);
    return ans;
}
/*更新同查詢*/
void updSon(int x,int c){
    update(1,1,n,id[x],id[x]+siz[x]-1,c);
}

int main(){
    memset(head,-1,sizeof head);
    n=read(),m=read(),rot=read(),mod=read();
    for(int i=1;i<=n;i++)w[i]=read();
    for(int i=1;i<=n-1;i++){
        int a=read(),b=read();
        addedge(a,b);
        addedge(b,a);
    }
    spilt();///剖分
    for(int i=1;i<=m;i++){
        int op,x,y,z;
        op=read();
        if(op == 1){
            x=read(),y=read(),z=read();
            updRange(x,y,z);
        }
        if(op == 2){
            x=read(),y=read();
            printf("%d\n",qRange(x,y));
        }
        if(op == 3){
            x=read(),y=read();
            updSon(x,y);
        }
        if(op == 4){
            x=read();
            printf("%d\n",qSon(x));
        }
    }
    return 0;
}

  

樹鏈剖分模板(洛谷P3384)