标签:using name pst base sum 依次 long 说明 bsp
如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作:
操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z
操作2: 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和
操作3: 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z
操作4: 格式: 4 x 表示求以x为根节点的子树内所有节点值之和
输入格式:
第一行包含4个正整数N、M、R、P,分别表示树的结点个数、操作个数、根节点序号和取模数(即所有的输出结果均对此取模)。
接下来一行包含N个非负整数,分别依次表示各个节点上初始的数值。
接下来N-1行每行包含两个整数x、y,表示点x和点y之间连有一条边(保证无环且连通)
接下来M行每行包含若干个正整数,每行表示一个操作,格式如下:
操作1: 1 x y z
操作2: 2 x y
操作3: 3 x z
操作4: 4 x
输出格式:
输出包含若干行,分别依次表示每个操作2或操作4所得的结果(对P取模)
时空限制:1s,128M
数据规模:
对于30%的数据:N≤10,M≤10
对于70%的数据: N≤103,M≤103
对于100%的数据: N≤105,M≤105
( 其实,纯随机生成的树LCA+暴力是能过的,可是,你觉得可能是纯随机的么233 )
样例说明:
树的结构如下:

各个操作如下:

故输出应依次为2、21(重要的事情说三遍:记得取模)
赛前提高一下码题能力.
吐槽一下,写了1hour的树剖【吐血】.
链接:https://www.luogu.org/problemnew/show/3384
AC代码:
#include<cstdio>
#include<iostream>
#define FOR(i,s,t) for(register int i=s;i<=t;++i)
typedef long long ll;
const int maxn=100011;
int n,m,r,p,type,x,y;
ll z;
int a[maxn];
#define VIS(now) for(register int e=las[now];e;e=nxt[e])
namespace TCP_And_BIT{
ll tr1[maxn],tr2[maxn],num[maxn];
inline int lowbit(int x){
return x&(-x);
}
inline void add(ll *r,int pos,ll x){
for(;pos<=n;r[pos]+=x,r[pos]%=p,pos+=lowbit(pos));return;
}
inline void _add(int l,int r,ll x){
x%=p;
add(tr1,l,x);add(tr1,r+1,(-x+p)%p);
add(tr2,l,1ll*(l-1)*x%p);add(tr2,r+1,1ll*(p-x)%p*r);
}
inline ll query(ll *r,int pos){
ll ans=0;for(;pos;ans+=r[pos],ans%=p,pos-=lowbit(pos));return ans;
}
inline ll _query(int l,int r){
ll sum1,sum2;
sum1=1ll*(l-1)*query(tr1,l-1)-1ll*query(tr2,l-1);
sum2=1ll*r*query(tr1,r)-1ll*query(tr2,r);
return (sum2-sum1+2*p)%p;
}
int nxt[maxn<<1],las[maxn],to[maxn<<1];
int dep[maxn],sz[maxn],f[maxn],top[maxn],xu[maxn];
int tot,dfn;
inline void insert(int x,int y){
nxt[++tot]=las[x];las[x]=tot;to[tot]=y;return;
}
inline void dfs1(int now){
sz[now]=1;
VIS(now)
if(!dep[to[e]]){
dep[to[e]]=dep[now]+1;f[to[e]]=now;
dfs1(to[e]);sz[now]+=sz[to[e]];
}
return;
}
inline void dfs2(int now,int chain){
xu[now]=++dfn;
num[dfn]=a[now];
top[now]=chain;
add(tr1,dfn,1ll*(num[dfn]-num[dfn-1]+p)%p);
add(tr2,dfn,1ll*(dfn-1)%p*(num[dfn]-num[dfn-1]+p)%p);
register int i=0;
VIS(now)if(to[e]!=f[now]&&sz[i]<sz[to[e]])i=to[e];
if(!i)return;
dfs2(i,chain);
VIS(now)if(to[e]!=f[now]&&i!=to[e])dfs2(to[e],to[e]);
return;
}
inline ll query_sum(int x,int y){
ll ans=0;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])x^=y^=x^=y;
ans+=_query(xu[top[x]],xu[x]);ans=(ans+2*p)%p;x=f[top[x]];
}
if(dep[x]<dep[y])x^=y^=x^=y;
ans+=_query(xu[y],xu[x]);ans=(ans+2*p)%p;
return ans;
}
inline void add_num(int x,int y,ll v){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])x^=y^=x^=y;
_add(xu[top[x]],xu[x],v);x=f[top[x]];
}
if(dep[x]<dep[y])x^=y^=x^=y;
_add(xu[y],xu[x],v);return ;
}
};
using namespace TCP_And_BIT;
int main(){
scanf("%d%d%d%d",&n,&m,&r,&p);
FOR(i,1,n)scanf("%d",a+i),a[i]%=p;
FOR(i,2,n){
scanf("%d%d",&x,&y);
insert(x,y);insert(y,x);
}
dep[r]=1;
dfs1(r);dfs2(r,r);
while(m--){
scanf("%d",&type);
if(type==1){
scanf("%d%d%lld",&x,&y,&z);
z%=p;
add_num(x,y,z);
}
if(type==2){
scanf("%d%d",&x,&y);
printf("%lld\n",(query_sum(x,y)+p)%p);
}
if(type==3){
scanf("%d%lld",&x,&z);
z%=p;
_add(xu[x],xu[x]+sz[x]-1,z);
}
if(type==4){
scanf("%d",&x);
printf("%lld\n",(_query(xu[x],xu[x]+sz[x]-1)+p)%p);
}
}
return 0;
}
标签:using name pst base sum 依次 long 说明 bsp
原文地址:http://www.cnblogs.com/Stump/p/7811768.html