树链剖分

搞了好几天终于把树剖模板过了
感觉最难理解的是对两点之间路径上的修改,我就是在这里被卡了好久
还是看注释吧
原题链接:https://www.luogu.org/problemnew/show/P3384

#include<bits/stdc++.h>
#define mid ((l+r)>>1)
#define sw(x,y) jzm=x,x=y,y=jzm;
#define For(i,j,k) for(int i=j;i<=k;++i)
using namespace std;
int read(){
    int x=0,l=1; char ch=getchar();
    while(!isdigit(ch)) {if (ch=='-') l=-1; ch=getchar();}
    while(isdigit(ch)) x=x*10+(ch^48),ch=getchar();
    return x*l;
}
typedef long long ll;
const int N=100005;
struct node{
    ll w,en;
}a[N*3];
int jzm,e,b[N],head[N],to[N<<1],nex[N<<1],mp[N],mp2[N];
void ad(int x,int y){
    to[++e]=y; nex[e]=head[x]; head[x]=e;
}
void bt(int x,int l,int r){
    if (l==r) {a[x].w=b[mp2[l]]; return;}
    bt(x<<1,l,mid); bt(x<<1|1,mid+1,r);
    a[x].w=a[x<<1].w+a[x<<1|1].w;
}
int xx,yy,n,m,r,p; ll k;
void pd(int fl,int l,int r){
    a[fl<<1].w+=a[fl].en*(mid-l+1);
    a[fl<<1|1].w+=a[fl].en*(r-mid);
    a[fl<<1].en+=a[fl].en;
    a[fl<<1|1].en+=a[fl].en;
    a[fl].en=0;
}
void add(int fl,int l,int r){
    if (l>=xx&&r<=yy){
        a[fl].w+=k*(r-l+1); a[fl].en+=k; return;
    }
    if (a[fl].en) pd(fl,l,r);
    if (mid>=xx) add(fl<<1,l,mid);
    if (mid<yy) add(fl<<1|1,mid+1,r);
    a[fl].w=a[fl<<1].w+a[fl<<1|1].w;
}
ll qu(int fl,int l,int r){
    if (l>=xx&&r<=yy) return a[fl].w;
    ll an=0;
    if (a[fl].en) pd(fl,l,r);
    if (mid>=xx) an+=qu(fl<<1,l,mid);
    if (mid<yy) an+=qu(fl<<1|1,mid+1,r);
    return an;
}
int cnt,siz[N],son[N],top[N],dep[N],fa[N];
void dfs1(int x,int de,int f){
    siz[x]=1; dep[x]=de++; fa[x]=f; int ma=0;
    for(int i=head[x];i;i=nex[i])
        if (to[i]!=f){
            dfs1(to[i],de,x);
            if (ma<siz[to[i]]) ma=siz[to[i]],son[x]=to[i];
            siz[x]+=siz[to[i]];
        }
}
void dfs2(int x,int tp){
    mp[x]=++cnt; top[x]=tp;
    if (son[x]){
        dfs2(son[x],tp);
        for(int i=head[x];i;i=nex[i])
            if (to[i]!=fa[x]&&to[i]!=son[x]) dfs2(to[i],to[i]);
    }
}
int main(){
    int x,y,fl,hk,wal,lca,de,f; ll ans; n=read(),m=read(),r=read(),p=read();
    For(i,1,n) b[i]=read();
    For(i,1,n-1){
        x=read(),y=read();
        ad(x,y); ad(y,x);
    }
    dfs1(r,1,0); dfs2(r,r);
    For(i,1,n) mp2[mp[i]]=i; bt(1,1,n);
    For(i,1,m){
        fl=read(),x=read();
        if (fl==3) xx=mp[x],yy=xx+siz[x]-1,k=read(),add(1,1,n);
        else if (fl==4) xx=mp[x],yy=xx+siz[x]-1,printf("%lld\n",qu(1,1,n)%p);
        else if (fl==2){
            y=read(); ans=0;
            while(top[x]!=top[y]){//当两个点不在同一条链上 
                if(dep[top[x]]<dep[top[y]]) sw(x,y);//把x点改为所在链顶端的深度更深的那个点
                xx=mp[top[x]]; yy=mp[x]; ans+=qu(1,1,n);//ans加上x点到x所在链顶端 这一段区间的点权和
                x=fa[top[x]];//把x跳到x所在链顶端的那个点的上面一个点
            }//直到两个点处于一条链上
            if(dep[x]>dep[y]) sw(x,y);//把x点变为深度更浅的那个点
            xx=mp[x]; yy=mp[y]; ans+=qu(1,1,n);//这时再加上此时两个点的区间和即可
            printf("%lld\n",ans%p);
        }
        //接下来同上
        else{
            y=read(); k=read();
            while(top[x]!=top[y]){
                if(dep[top[x]]<dep[top[y]]) sw(x,y);
                xx=mp[top[x]]; yy=mp[x]; add(1,1,n);
                x=fa[top[x]];
            }
            if(dep[x]>dep[y]) sw(x,y);
            xx=mp[x]; yy=mp[y]; add(1,1,n);
        }
    }
    return 0;
}
posted @ 2017-12-05 20:45  wjy666  阅读(235)  评论(0编辑  收藏  举报