玄关求调,37pts,只A1,2,3,11

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

stickman_stickmin @ 2024-06-26 18:22:53

如标题,已经查了很久步步取模,查逻辑也感觉没问题 代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
struct tree{
    long long val,l,r,add;
}t[4*N+10];
long long n,m,s,mod;
long long w[N],w_new[N];
int ls(int p){return p<<1;}
int rs(int p){return p<<1|1;}
void addtag(int p,int d){
    t[p].add+=d;
    t[p].val+=d*(t[p].r-t[p].l+1);
    t[p].val%=mod;
}
void push_up(int p){
    t[p].val=t[ls(p)].val+t[rs(p)].val;
    t[p].val%=mod;
}
void push_down(int p){//下传标记
    if(t[p].add){
        addtag(ls(p),t[p].add);
        addtag(rs(p),t[p].add);
        t[p].add=0;
    }
}
void build(int p,int l,int r){
    t[p].l=l,t[p].r=r;
    if(l==r){
        t[p].val=w_new[l];//依照树的dfn序建树,而非原序列
        t[p].val%=mod;
        return;
    }
    int mid=(t[p].l+t[p].r)>>1;
    build(p*2,l,mid);
    build(p*2+1,mid+1,r);
    push_up(p);
}
void update(int p,int l,int r,int k){//线段树区间求和 p=1
    if(l<=t[p].l && r>=t[p].r){
        addtag(p,k);
        return;
    }
    push_down(p);
    int mid=(t[p].l+t[p].r)>>1;
    if(l<=mid)update(ls(p),l,r,k);
    if(r>mid)update(rs(p),l,r,k);
    push_up(p);
}
int query(int p,int l,int r){//线段树区间求和  p=1
    if(l<=t[p].l && r>=t[p].r){
        return t[p].val%=mod;
    }
    push_down(p);
    int ans=0;
    int mid=(t[p].l+t[p].r)>>1;
    if(l<=mid)ans+=query(ls(p),l,r);
    if(r>mid)ans+=query(rs(p),l,r);
    return ans;//后面用到ans时在后面取模
}

struct node{
    int to,nxt;
}edge[2*N];//无向图,边x2
int cnt,head[N*2];
void prework(){
    for(int i=0;i<N*2;i++){
        head[i]=-1;edge[i].nxt=-1;
    }
    cnt=0;
}
void adg(int u,int v){
    edge[cnt].to=v,edge[cnt].nxt=head[u],head[u]=cnt++;
}
int dep[N],siz[N],son[N],top[N],fat[N],id[N];
int num=0;
void dfs1(int u,int fa){//收集链上有关数据
    dep[u]=dep[fa]+1;
    fat[u]=fa;
    siz[u]=1;
    for(int i=head[u];~i;i=edge[i].nxt){
        int v=edge[i].to;
        if(v!=fa){
            fat[v]=u;
            dfs1(v,u);
            siz[u]+=siz[v];//回溯后,将v的儿子数加到u上
            if(!son[u]||siz[son[u]]<siz[v])//标记每个非叶子的重节点
                son[u]=v;
        }
    }
}
void dfs2(int x,int topx){//根据数据进一步得出另一些数据
    id[x]=++num;
    w_new[num]=w[x];//把每个节点初始值赋给新节点
    top[x]=topx;//u所在链头
    if(!son[x])return;//u是叶子,无儿子,返回
    dfs2(son[x],topx);//优先dfs重儿子
    for(int i=head[x];~i;i=edge[i].nxt){
        int v=edge[i].to;
        if(v!=fat[x] && v!=son[x]){
        //无向图父亲显然不行    重儿子已经整过了
            dfs2(v,v);//每个轻儿子都有 以他为头 的重链
        }
    }
}

void update_range(int x,int y,int z){//节点最短路径上节点赋值
    while(top[x]!=top[y]){//不在同一条链
        if(dep[top[x]]<dep[top[y]])swap(x,y);//以x为操作对象,要求x所在链的顶更深
        update(1,id[top[x]],id[x],z);
        x=fat[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);//循环结束,x,y在同一链上
    update(1,id[x],id[y],z);
}
int query_range(int x,int y){//节点最短路径上节点值和
    int ans=0;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        ans+=query(1,id[x],id[top[x]]);
        ans%=mod;
        x=fat[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);//若LCA=y,则交换x,y使得x更浅,使得id[x]<=id[y]
    ans+=query(1,id[x],id[y]);
    return ans%mod;
}

void update_tree(int x,int k){//x子树节点赋值
    update(1,id[x],id[x]+siz[x]-1,k);
}
int query_tree(int x){//x子树节点和
    return query(1,id[x],id[x]+siz[x]-1)%mod;
}
signed main(){
    prework();
    cin>>n>>m>>s>>mod;
    for(int i=1;i<=n;i++)cin>>w[i];
    for(int i=1;i<=n-1;i++){
        int u,v;
        cin>>u>>v;
        adg(u,v);
        adg(v,u);
    }
    dfs1(s,0);
    dfs2(s,s);
    build(1,1,n);
    while(m--){
        int op,x,y,z;
        cin>>op;
        switch(op){
            case 1:
                cin>>x>>y>>z;
                update_range(x,y,z);
                break;
            case 2:
                cin>>x>>y;
                cout<<query_range(x,y)<<'\n';
                break;
            case 3:
                cin>>x>>z;
                update_tree(x,z);
                break;
            case 4:
                cin>>x;
                cout<<query_tree(x)<<'\n';
                break;
        }
    }

    return 0;
}

by stickman_stickmin @ 2024-06-27 18:22:02

此贴已结,

line120

应当为
ans+=query(1,id[top[x]],id[x]);
id[top[x]]在树中的dfn序在id[x]前面

by oliver326 @ 2024-07-04 20:25:02

哇哇哇,谢谢巨佬提醒!写的时候不动脑子全弄反了:(


by newtocpp @ 2024-08-10 18:36:19

%%%


|