树剖求调

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

microchip @ 2024-04-19 22:07:00

9分,第三点AC,其它全WA

#include<bits/stdc++.h>
using namespace std;

const int maxn=100050;
int n,m,r,p,val[maxn],op,x,y,z,T[4*maxn],tag[4*maxn],len[4*maxn],tmp[maxn];
int dfn[maxn],tp[maxn],siz[maxn],depth[maxn],fa[maxn],heavy[maxn],nth,bottom[maxn];
vector<int> Tree[maxn];

void build_tree(int l,int r,int no){//线段树建树
    len[no]=r-l+1;
    if(l==r){
        T[no]=tmp[l];
        return;
    }int mid=(l+r)/2;
    build_tree(l,mid,no<<1);
    build_tree(mid+1,r,(no<<1)|1);
    T[no]=(T[no<<1]+T[(no<<1)|1])%p;
}

void update(int no){//标记更新(就是pushdown)
    T[no<<1]+=tag[no]*len[no<<1];
    T[no<<1]%=p;
    T[(no<<1)|1]+=tag[no]*len[(no<<1)|1];
    T[(no<<1)|1]%=p;
    tag[no<<1]+=tag[no];
    tag[no<<1]%=p;
    tag[(no<<1)|1]+=tag[no];
    tag[(no<<1)|1]%=p;
    tag[no]=0;
}

int sum(int l,int r,int no,int L,int R){//线段树求和
    if(l>R||r<L)return 0;
    if(l>=L&&r<=R)return T[no];
    update(no);
    int ret=0,mid=(l+r)/2;
    ret+=sum(l,mid,no<<1,L,R);
    ret+=sum(mid+1,r,(no<<1)|1,L,R);
    return ret%p;
}

void add(int l,int r,int no,int v,int L,int R){//线段树区间加
    if(l>R||r<L)return;
    if(l>=L&&r<=R){
        T[no]+=(r-l+1)*v;
        tag[no]+=v;
        return;
    }update(no);
    int mid=(l+r)/2;
    add(l,mid,no<<1,v,L,R);
    add(mid+1,r,(no<<1)|1,v,L,R);
}

void dfs1(int no,int deep){
    siz[no]=1;
    depth[no]=deep;
    int hson=-1,maxn=-1;
    for(unsigned int i=0;i<Tree[no].size();i++){
        if(siz[Tree[no][i]]==0){
            fa[Tree[no][i]]=no;
            dfs1(Tree[no][i],deep+1);
            siz[no]+=siz[Tree[no][i]];
            if(maxn<siz[Tree[no][i]]){hson=Tree[no][i];maxn=siz[Tree[no][i]];}
        }
    }heavy[no]=hson;
}

void dfs2(int no,int t){
    if(dfn[no])return;
    dfn[no]=++nth;
    bottom[no]=dfn[no];
    tmp[nth]=val[no];
    tp[no]=t;
    if(heavy[no]!=-1){dfs2(heavy[no],t);bottom[no]=max(bottom[no],bottom[heavy[no]]);}
    for(unsigned int i=0;i<Tree[no].size();i++){
        if(dfn[Tree[no][i]]==0){
            dfs2(Tree[no][i],Tree[no][i]);
            bottom[no]=max(bottom[no],bottom[Tree[no][i]]);
        }
    }
}

int link_sum(int xx,int yy){//树剖路径和
    int ret=0;
    while(tp[xx]!=tp[yy]){
        if(depth[tp[xx]]<depth[tp[yy]])swap(xx,yy);
        ret+=sum(1,n,1,dfn[tp[xx]],dfn[xx]);
        ret%=p;
        xx=fa[tp[xx]];
    }ret+=sum(1,n,1,dfn[xx],dfn[yy]);
    return ret%p;
}

void link_add(int xx,int yy,int v){//树剖加
    while(tp[xx]!=tp[yy]){
        if(depth[tp[xx]]<depth[tp[yy]])swap(xx,yy);
        add(1,n,1,v%p,dfn[tp[xx]],dfn[xx]);
        xx=fa[tp[xx]];
    }add(1,n,1,v,dfn[xx],dfn[yy]);
}

int sub_sum(int xx){//树剖子树和
    return sum(1,n,1,dfn[xx],bottom[xx]);
}

void sub_add(int xx,int v){//树剖子树加
    add(1,n,1,v%p,dfn[xx],bottom[xx]);
}

int main()
{
//  freopen("input.txt","r",stdin);
    cin>>n>>m>>r>>p;
    for(int i=1;i<=n;i++)cin>>val[i];
    for(int i=1;i<n;i++){
        cin>>x>>y;
        Tree[x].push_back(y);
        Tree[y].push_back(x);
    }dfs1(r,1);
    dfs2(r,r);
    build_tree(1,n,1);
    while(m--){
        cin>>op;
        switch(op){
            case 1:{
                cin>>x>>y>>z;
                link_add(x,y,z);
                break;
            }case 2:{
                cin>>x>>y;
                cout<<link_sum(x,y)<<endl;
                break;
            }case 3:{
                cin>>x>>z;
                sub_add(x,z);
                break;
            }case 4:{
                cin>>x;
                cout<<sub_sum(x)<<endl;
                break;
            }default:break;
        }
    }
    return 0;
}

by wangzhiyuan123 @ 2024-04-21 18:58:04

区间加那里会不会炸int


by microchip @ 2024-04-23 19:31:45

调出来了:

1.线段树我没有pushup(我是sb)

2.链上修改和求和while循环后面要加一个这个:

if(dfn[xx]>dfn[yy])swap(xx,yy);


|