数据是否过水

P3384 【模板】重链剖分/树链剖分

Qerucy @ 2024-08-02 14:29:43

rt,重儿子换成第一个儿子然后过了,跑得比重链剖分还快。

代码:

#include<bits/stdc++.h>

using namespace std;

const int N=4e5+10;

int n,m,r,p;
int a[N];
int an[N];
int deep[N];
int siz[N];
int fa[N];
int son[N];
int id[N];
int cnt;
int top[N];
int tree[N];
int lazy[N];
int res;

vector<int>v[N];

void dfs1(int x,int f,int de){
    deep[x]=de;
    fa[x]=f;
    siz[x]=1;
    for(int i=0;i<v[x].size();i++){
        int y=v[x][i];
        if(y==f) continue;
        dfs1(y,x,de+1);
        siz[x]+=siz[y];
        if(!son[x]){
            son[x]=y;
        }
    }
}

void dfs2(int x,int topfa){
    id[x]=++cnt;
    an[cnt]=a[x];
    top[x]=topfa;

    if(!son[x]) return;
    dfs2(son[x],topfa);

    for(int i=0;i<v[x].size();i++){
        int y=v[x][i];
        if(y==fa[x]||y==son[x]) continue;
        dfs2(y,y);
    }
}

void build(int rt,int l,int r){
    if(l==r){
        tree[rt]=an[l];
        tree[rt]%=p;
        return;
    }
    int mid=(l+r)/2;
    build(rt*2,l,mid);
    build(rt*2+1,mid+1,r);
    tree[rt]=(tree[rt*2]+tree[rt*2+1])%p;
}

void pushdown(int rt,int len){
    lazy[rt*2]+=lazy[rt];
    lazy[rt*2+1]+=lazy[rt];
    tree[rt*2]+=lazy[rt]*(len-len/2);
    tree[rt*2+1]+=lazy[rt]*(len/2);
    tree[rt*2]%=p;
    tree[rt*2+1]%=p;
    lazy[rt]=0;
}

void update(int rt,int l,int r,int L,int R,int k){
    if(L<=l&&r<=R){
        lazy[rt]+=k;
        tree[rt]+=k*(r-l+1);
        return;
    }
    if(lazy[rt]) pushdown(rt,r-l+1);
    int mid=(l+r)/2;
    if(L<=mid) update(rt*2,l,mid,L,R,k);
    if(R>mid) update(rt*2+1,mid+1,r,L,R,k);
    tree[rt]=(tree[rt*2]+tree[rt*2+1])%p;
}

void query(int rt,int l,int r,int L,int R){
    if(L<=l&&r<=R){
        res+=tree[rt];
        res%=p;
        return;
    }
    if(lazy[rt]) pushdown(rt,r-l+1);
    int mid=(l+r)/2;
    if(L<=mid) query(rt*2,l,mid,L,R);
    if(R>mid) query(rt*2+1,mid+1,r,L,R);
}

void updateL(int x,int y,int z){
    z%=p;
    while(top[x]!=top[y]){
        if(deep[top[x]]<deep[top[y]]){
            swap(x,y);
        }
        update(1,1,n,id[top[x]],id[x],z);
        x=fa[top[x]];
    }
    if(deep[x]>deep[y]) swap(x,y);
    update(1,1,n,id[x],id[y],z);
}

int queryL(int x,int y){
    int ans=0;
    while(top[x]!=top[y]){
        if(deep[top[x]]<deep[top[y]]){
            swap(x,y);
        }
        res=0;
        query(1,1,n,id[top[x]],id[x]);
        ans+=res;
        ans%=p;
        x=fa[top[x]];
    }
    if(deep[x]>deep[y]) swap(x,y);
    res=0;
    query(1,1,n,id[x],id[y]);
    ans+=res;
    return ans%p;
}

void updateS(int x,int z){
    update(1,1,n,id[x],id[x]+siz[x]-1,z);
}

int queryS(int x){
    res=0;
    query(1,1,n,id[x],id[x]+siz[x]-1);
    return res%p;
}

int main(){
    scanf("%d%d%d%d",&n,&m,&r,&p);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    for(int i=1;i<=n-1;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        v[x].push_back(y);
        v[y].push_back(x);
    }
    dfs1(r,0,1);
    dfs2(r,r);
    build(1,1,n);
    while(m--){
        int op,x,y,z;
        scanf("%d",&op);
        if(op==1){
            scanf("%d%d%d",&x,&y,&z);
            updateL(x,y,z);
        }
        if(op==2){
            scanf("%d%d",&x,&y);
            printf("%d\n",queryL(x,y));
        }
        if(op==3){
            scanf("%d%d",&x,&z);
            updateS(x,z);
        }
        if(op==4){
            scanf("%d",&x);
            printf("%d\n",queryS(x));
        }
    }
    return 0;
}

by DWT8125 @ 2024-08-02 16:45:10

@Revdream 不发你的定链剖分?


by Qerucy @ 2024-08-02 18:18:56

@DWT8125 定链剖分过不去


by DWT8125 @ 2024-08-02 18:22:17

@Revdream 我说的是你固定取一个点的那份


by osfly @ 2024-08-02 21:24:51

@Revdream 弗如阳寿剖分


by Qerucy @ 2024-08-02 21:34:56

@osfly 写不了,用ran老是re


by dctc800d @ 2024-08-06 21:27:45

我73


|