对 应 对应 对应洛谷P3384 【模板】轻重链剖分
#include
using namespace std;
#define GO std::ios::sync_with_stdio(false)
const int maxn=4e5+10;
int n,m,root,w[maxn],mod;
struct edge{
int to,nxt;
}d[maxn]; int head[maxn],k=1;
void add(int u,int v){
d[k].to=v,d[k].nxt=head[u],head[u]=k++;
}
int deep[maxn],siz[maxn],fa[maxn], son[maxn];
void dfs1(int u,int f,int depth)
{
deep[u]=depth, fa[u]=f, siz[u]=1;
int maxson=-1;
for(int i=head[u];i;i=d[i].nxt)
{
int v=d[i].to;
if( v==f ) continue;
dfs1(v,u,depth+1);
siz[u]+=siz[v];
if(siz[v]>maxson) maxson=siz[v],son[u]=v;
}
}
int id[maxn],wn[maxn],top[maxn],cnt;
void dfs2(int u,int ffa)
{
id[u]=++cnt, wn[cnt]=w[u], top[u]=ffa;
if( son[u]==0 ) return;
dfs2( son[u],ffa );
for(int i=head[u];i;i=d[i].nxt)
{
int v=d[i].to;
if( v==fa[u] || v==son[u] ) continue;
dfs2(v,v);
}
}
struct tree{
int v,l,r,lazy;
}a[maxn];
void push_down(int p)
{
if( !a[p].lazy ) return;
int len1=a[p<<1].r-a[p<<1].l+1, len2=a[p<<1|1].r-a[p<<1|1].l+1;
a[p<<1].lazy = (a[p<<1].lazy + a[p].lazy)%mod;
a[p<<1|1].lazy = (a[p<<1|1].lazy + a[p].lazy)%mod;
a[p<<1].v=(a[p<<1].v+a[p].lazy*len1%mod)%mod;
a[p<<1|1].v = (a[p<<1|1].v+a[p].lazy*len2%mod)%mod;
a[p].lazy=0;
}
void build(int p,int l,int r)
{
a[p].l=l,a[p].r=r,a[p].lazy=0;
if( l==r )
{
a[p].v=wn[l]%mod;
return;
}
int mid = l+r>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
a[p].v = (a[p<<1].v+a[p<<1|1].v)%mod;
}
void tree_add(int p,int l,int r,int k)
{
if( l<=a[p].l&&a[p].r<=r)
{
a[p].v=( (a[p].r-a[p].l+1) *k+a[p].v)%mod;
a[p].lazy=(a[p].lazy+k)%mod;
return;
}
push_down(p);
int mid=a[p].l+a[p].r>>1;
if(l<=mid) tree_add(p<<1,l,r,k);
if(r>mid) tree_add(p<<1|1,l,r,k);
a[p].v = (a[p<<1].v+a[p<<1|1].v)%mod;
}
int tree_ask(int p,int l,int r)
{
if( l<=a[p].l&&a[p].r<=r) return a[p].v;
push_down(p);
int mid=a[p].l+a[p].r>>1,ans=0;
if(l<=mid) ans=(ans + tree_ask(p<<1,l,r) )%mod;
if(r>mid) ans=(ans + tree_ask(p<<1|1,l,r) )%mod;
return ans;
}
void tree_addpath(int x,int y,int k)//x到y的路上加上k
{
while(top[x] != top[y])
{
if( deep[ top[x] ]deep[y] ) swap(x,y);
tree_add(1,id[x],id[y],k);
}
int tree_asksum(int x,int y)
{
int ans=0;
while( top[x]!=top[y] )
{
if( deep[ top[x] ]deep[y] ) swap(x,y);
ans= (ans+tree_ask(1,id[x],id[y]) )%mod;
return ans;
}
void tree_addroot(int root,int k)
{
tree_add(1,id[root],id[root]+siz[root]-1,k);
}
int tree_askrootsum(int root)
{
int ans=tree_ask(1,id[root],id[root]+siz[root]-1)%mod;
return ans;
}
int main()
{
GO;
cin.tie(0); cout.tie(0);
cin >> n >> m >> root >> mod;
for(int i=1;i<=n;i++) cin >> w[i];
for(int i=1, l, r;i> l >> r;
add(l,r); add(r,l);
}
dfs1(root,0,1);
dfs2(root,root);
build(1,1,n);
for(int i=1, a1, a2, a3, a4;i<=m;i++)
{
cin >> a1;
if( a1==1 )
{
cin >> a2 >> a3 >> a4;
tree_addpath(a2,a3,a4%mod);
}
else if( a1==2 )
{
cin >> a2 >> a3;
cout << tree_asksum(a2,a3) << "\n";
}
else if( a1==3 )
{
cin >> a2 >> a3;
tree_addroot(a2,a3);
}
else
{
cin >> a2;
cout << tree_askrootsum(a2) << "\n";
}
}
return 0;
}