73pts求调

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

bsjsaikou10 @ 2023-08-29 09:40:42

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
typedef struct node{
    int to,w,next;
}node;
node edge[MAXN];
int head[MAXN],dfn[MAXN],fa[MAXN],dep[MAXN],sz[MAXN],wc[MAXN],topp[MAXN],rdfn[MAXN],a[MAXN];
long long w[MAXN << 2],tag[MAXN << 2];
int cnt,n,r,p,m,vistime;
void add_edge(int u,int v,int w){
    edge[++cnt].to = v;
    edge[cnt].w = w;
    edge[cnt].next = head[u];
    head[u] = cnt;
    return;
}
void init(){
    memset(head,-1,sizeof(head));
    return;
}
void dfs_rechain(int u,int f){
    fa[u] = f;
    sz[u] = 1;
    dep[u] = dep[f] + 1;
    for(int i = head[u]; i ^ -1; i = edge[i].next){
        int v = edge[i].to;
        if(!(v ^ f)){
            continue;
        }
        dfs_rechain(v,u);
        sz[u] += sz[v];
        if(sz[v] > sz[wc[u]]){
            wc[u] = v;
        }
    }
    return;
}
void dfs_dfn(int u,int top){
    topp[u] = top;
    dfn[u] = ++vistime;
    rdfn[vistime] = u;
    if(!wc[u]){
        return;
    }
    if(wc[u]){
        dfs_dfn(wc[u],top);
    }
    for(int i = head[u]; i ^ -1; i = edge[i].next){
        int v = edge[i].to;
        if(!(v ^ fa[u]) || !(v ^ wc[u])){
            continue;
        }
        dfs_dfn(v,v);
    }
    return;
}
void dfs(){
    dfs_rechain(r,0);
    dfs_dfn(r,0);
    return;
}
void pushup(int u){
    w[u] = (w[u << 1] + w[(u << 1) | 1]) % p;
    return;
}
void build(int u,int L,int R){
    if(!(L ^ R)){
        w[u] = a[rdfn[L]];
        return;
    }
    int mid = (L + R) >> 1;
    build(u << 1,L,mid);
    build((u << 1) | 1,mid + 1,R);
    pushup(u);
    return;
}
bool inRange(int L,int R,int l,int r){
    return (l <= L) && (R <= r);
}
bool outRange(int L,int R,int l,int r){
    return (L > r) || (R < l);
}
void makeTag(int u,int len,long long x){
    tag[u] += x;
    w[u] += len * x % p;
    tag[u] %= p;
    w[u] %= p;
    return;
}
void pushdown(int u,int L,int R){
    int mid = (L + R) >> 1;
    makeTag(u << 1,mid - L + 1,tag[u]);
    makeTag((u << 1) | 1,R - mid,tag[u]);
    tag[u] = 0;
    return;
}
int query(int u,int L,int R,int l,int r){
    if(inRange(L,R,l,r)){
        return w[u];
    }
    if(!outRange(L,R,l,r)){
        int mid = (L + R) >> 1;
        pushdown(u,L,R);
        return (query(u << 1,L,mid,l,r) + query((u << 1) | 1,mid + 1,R,l,r)) % p;
    }
    return 0;
}
void update(int u,int L,int R,int l,int r,long long x){
    if(inRange(L,R,l,r)){
        makeTag(u,R - L + 1,x);
        return;
    }
    if(!outRange(L,R,l,r)){
        int mid = (L + R) >> 1;
        pushdown(u,L,R);
        update(u << 1,L,mid,l,r,x);
        update((u << 1) | 1,mid + 1,R,l,r,x);
        pushup(u);
    }
    return;
}
void upd(int x,int y,int z){
    while(topp[x] ^ topp[y]){
        if(dep[topp[x]] < dep[topp[y]]){
            swap(x,y);
        }
        update(1,1,n,dfn[topp[x]],dfn[x],z);
        x = fa[topp[x]];
    }
    update(1,1,n,min(dfn[x],dfn[y]),max(dfn[x],dfn[y]),z);
    return;
}
int qry(int x,int y){
    long long ans = 0;
    while(topp[x] ^ topp[y]){
        if(dep[topp[x]] < dep[topp[y]]){
            swap(x,y);
        }
        ans += query(1,1,n,dfn[topp[x]],dfn[x]);
        ans %= p;
        x = fa[topp[x]];
    }
    return (ans + query(1,1,n,min(dfn[x],dfn[y]),max(dfn[x],dfn[y]))) % p;;
}
int main(){
    init();
    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; i++){
        int u,v;
        scanf("%d%d",&u,&v);
        add_edge(u,v,0);
        add_edge(v,u,0);
    }
    dfs();
    build(1,1,n);
    for(int i = 1; i <= m; i++){
        int opt,x,y,z;
        scanf("%d",&opt);
        if(!(opt ^ 1)){
            scanf("%d%d%d",&x,&y,&z);
            upd(x,y,z);
        }
        else if(!(opt ^ 2)){
            scanf("%d%d",&x,&y);
            printf("%d\n",qry(x,y));
        }
        else if(!(opt ^ 3)){
            scanf("%d%d",&x,&y);
            update(1,1,n,dfn[x],dfn[x] + sz[x] - 1,y);
        }
        else{
            scanf("%d",&x);
            printf("%lld\n",query(1,1,n,dfn[x],dfn[x] + sz[x] - 1) % p);
        }
    }
    return 0;
}

by bsjsaikou10 @ 2023-08-29 09:42:52

MAXN开到1e5 + 8就MLE三个点,开到1e5 + 5就TLE两个,WA一个


by bsjsaikou10 @ 2023-08-29 09:44:11

MAXN等于1e5 + 8时的提交记录: https://www.luogu.com.cn/record/123169864 MAXN等于1e5 + 5时的提交记录: https://www.luogu.com.cn/record/123170073


by bsjsaikou10 @ 2023-08-29 09:51:05

破案了,警示后人,用链式前向星存无向图的边数组记得乘2!


by helloworld131 @ 2023-08-29 10:27:16


by helloworld131 @ 2023-08-29 10:27:44

佬薄纱蓝题


|