信息学奥赛一本通1764:社会送温暖
事先说明,本文附的代码为ai生成,因为本人是初三牲,没多少时间QWQ,望理解
原题链接:https://ybt.ssoier.cn/problem_show.php?pid=1764
【题目描述】
社会送温暖有非常多的体现方式,小G正在思考其中的一种:
我们可以把社会看做一个n个节点的树,由n−1条边连接,节点从1编号,每个节点有一定财富值,用金币数描述。
每次社会送温暖时,他会选择两个节点,对链接它们的道路上的点,采用这么几种方式:
①.按顺序加金币数,第一个加a,第二个加a+d,第三个加a+2d,以此类推。
②.按顺序加金币数,第一个加a,第二个加2a,第三个加4a,以此类推。
③.按顺序改金币数,第一个改为a,第二个改为a+d,第三个改为a+2d,以此类推。
④.按顺序改金币数,第一个改为a,第二个改为2a,第三个改为4a,以此类推。
有时社会送温暖还要考虑两个点路径间的民众反映,所以会询问路径上的金币数和,你要告诉他答案模P的值。
【输入】
第一行三个数n,q,P,分别表示节点数、操作数、和模数。
接下来n−1行每行两个整数表示一条边。
接下来1行n个整数,第i个整数Ai表示这个点上初始的金币数。
接下来q行每行三个数op,u,v,表示操作类型与操作的两个点。
若op=1或op=3,则这行后还会接两个整数a和d,如题面所描述;若op=2或op=4,则这行后还会接一个整数a;若op=5,则表示询问。
【输出】
对每个询问操作输出一行作为答案。
【输入样例】
5 5 29311
1 3
5 3
4 3
3 2
24701 12247 27130 27071 4060
4 5 1 27096
4 2 3 17348
3 1 2 8785 8918
5 3 5
4 2 1 2936
【输出样例】
15488
【提示】
【数据规模】
20%的数据:\(n,q≤1000\)。
40%的数据:\(n,q≤10000\)。
另有30%的数据:树是一条链。
100%的数据:\(1≤n,q≤10^5;1≤P≤10^7;0≤A_i,d,a≤2^{31}\)。
首先,这个是一个树链剖分的题很显然可以看出来(其实是分类里写了),那我们就先进行树剖,然后把问题就转换成一个序列加或替换成一个等差数列或等比数列。
我们先考虑等差数列怎么办,离线的做法当然是差分啦,但是他要求在线,那直接用线段树,在懒更新上做文章,具体地,我们把懒更新的内容换成A,B两个懒更新数组,表示等差数列的首项和公差,然后sum线段树就直接用求和公式算。
接下来考虑下发,这也简单,因为一个等差数列+另一个等差数列还是等差数列,首项和公差直接相加就行。
覆盖就不用我多说了把,直接把sum和懒更新清空,然后赋值。
接下来就是等比数列的内容,这个可以直接从等差数列哪里类比过来,然后因为公比为2,只需要维护一个首项就完事了。
核心的解决了,难的其实是这些不核心的(毒瘤)内容。
1.他树链剖分,是有顺序的,所以要正反都开一个数组处理,但是等差数列其实可以优化一下,我们把倒着的看成公差为负的等差数列就可以了,但是等比数列不行,必须要同时维护两个数组。
2.取模要小心,必要时不要吝啬自己的代码,我当时写了有两百行给我道心写崩了。
然后就是计算一下公式,然后当模拟题来写吧。
code(AI):
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
const int N=100005;
ll read(){
ll k=0,f=1;char c=getchar();
for(;c<'0'||c>'9';c=getchar())if(c=='-')f=-1;
for(;c>='0'&&c<='9';c=getchar())k=k*10+c-'0';
return k*f;
}
int n,q;
ll P;
vector<int>G[N];
ll a[N];
int dfn[N],fa[N],dep[N],seg[N],siz[N],son[N],top[N],idx=1;
ll pw2[N];
ll sum[N<<2],A[N<<2],B[N<<2],C[N<<2],D[N<<2];
ll norm(ll x){
x%=P;
if(x<0)x+=P;
return x;
}
ll ap_sum(ll x,ll d,int len){
return (1LL*len*(2*x+1LL*(len-1)*d)/2)%P;
}
ll gp_sum(ll x,int len){
return x*(pw2[len]-1)%P;
}
void dfs1(int u,int f){
siz[u]=1;
dep[u]=dep[f]+1;
fa[u]=f;
for(int v:G[u]){
if(v==f)continue;
dfs1(v,u);
siz[u]+=siz[v];
if(son[u]==0||siz[son[u]]<siz[v])son[u]=v;
}
}
void dfs2(int u,int f,int t){
seg[idx]=u;
dfn[u]=idx++;
top[u]=t;
if(!son[u])return;
dfs2(son[u],u,t);
for(int v:G[u]){
if(v==f||v==son[u])continue;
dfs2(v,u,v);
}
}
void add_lazy(int p,ll x,ll d,int len){
sum[p]=norm(sum[p]+ap_sum(x,d,len));
if(A[p]>=P)A[p]=P+norm(A[p]-P+x);
else A[p]=norm(A[p]+x);
B[p]=norm(B[p]+d);
}
void mul1_lazy(int p,ll x,int len){
sum[p]=norm(sum[p]+gp_sum(x,len));
C[p]=norm(C[p]+x);
}
void mul2_lazy(int p,ll x,int len){
sum[p]=norm(sum[p]+gp_sum(x,len));
D[p]=norm(D[p]+x);
}
void set_lazy(int p,ll x,ll d,ll c,ll e,int len){
sum[p]=norm(ap_sum(x,d,len)+gp_sum(c,len)+gp_sum(e,len));
A[p]=P+norm(x);
B[p]=norm(d);
C[p]=norm(c);
D[p]=norm(e);
}
void down(int p,int ln,int rn){
if(!(A[p]||B[p]||C[p]||D[p]))return;
if(A[p]>=P){
ll x=A[p]-P;
set_lazy(p<<1,x,B[p],C[p],D[p]*pw2[rn]%P,ln);
set_lazy(p<<1|1,norm(x+1LL*ln*B[p]),B[p],C[p]*pw2[ln]%P,D[p],rn);
}
else{
add_lazy(p<<1,A[p],B[p],ln);
add_lazy(p<<1|1,norm(A[p]+1LL*ln*B[p]),B[p],rn);
mul1_lazy(p<<1,C[p],ln);
mul1_lazy(p<<1|1,C[p]*pw2[ln]%P,rn);
mul2_lazy(p<<1,D[p]*pw2[rn]%P,ln);
mul2_lazy(p<<1|1,D[p],rn);
}
A[p]=B[p]=C[p]=D[p]=0;
}
void build(int l,int r,int p){
A[p]=B[p]=C[p]=D[p]=0;
if(l==r){
sum[p]=a[seg[l]];
return;
}
int mid=(l+r)>>1;
build(l,mid,p<<1);
build(mid+1,r,p<<1|1);
sum[p]=norm(sum[p<<1]+sum[p<<1|1]);
}
void add(int ql,int qr,ll x,ll d,int l,int r,int p){
if(ql<=l&&r<=qr){
add_lazy(p,x,d,r-l+1);
}
else{
int mid=(l+r)>>1;
down(p,mid-l+1,r-mid);
int s=max(ql,l);
if(ql<=mid)add(ql,qr,x,d,l,mid,p<<1);
if(qr>mid){
int t=max(ql,mid+1);
add(ql,qr,norm(x+1LL*(t-s)*d),d,mid+1,r,p<<1|1);
}
sum[p]=norm(sum[p<<1]+sum[p<<1|1]);
}
}
void mul1(int ql,int qr,ll x,int l,int r,int p){
if(ql<=l&&r<=qr){
mul1_lazy(p,x,r-l+1);
}
else{
int mid=(l+r)>>1;
down(p,mid-l+1,r-mid);
int s=max(ql,l);
if(ql<=mid)mul1(ql,qr,x,l,mid,p<<1);
if(qr>mid){
int t=max(ql,mid+1);
mul1(ql,qr,x*pw2[t-s]%P,mid+1,r,p<<1|1);
}
sum[p]=norm(sum[p<<1]+sum[p<<1|1]);
}
}
void mul2(int ql,int qr,ll x,int l,int r,int p){
if(ql<=l&&r<=qr){
mul2_lazy(p,x,r-l+1);
}
else{
int mid=(l+r)>>1;
down(p,mid-l+1,r-mid);
int t=min(qr,r);
if(ql<=mid){
int s=min(qr,mid);
mul2(ql,qr,x*pw2[t-s]%P,l,mid,p<<1);
}
if(qr>mid)mul2(ql,qr,x,mid+1,r,p<<1|1);
sum[p]=norm(sum[p<<1]+sum[p<<1|1]);
}
}
void change(int ql,int qr,ll x,ll d,int l,int r,int p){
if(ql<=l&&r<=qr){
set_lazy(p,x,d,0,0,r-l+1);
}
else{
int mid=(l+r)>>1;
down(p,mid-l+1,r-mid);
int s=max(ql,l);
if(ql<=mid)change(ql,qr,x,d,l,mid,p<<1);
if(qr>mid){
int t=max(ql,mid+1);
change(ql,qr,norm(x+1LL*(t-s)*d),d,mid+1,r,p<<1|1);
}
sum[p]=norm(sum[p<<1]+sum[p<<1|1]);
}
}
void change1(int ql,int qr,ll x,int l,int r,int p){
if(ql<=l&&r<=qr){
set_lazy(p,0,0,x,0,r-l+1);
}
else{
int mid=(l+r)>>1;
down(p,mid-l+1,r-mid);
int s=max(ql,l);
if(ql<=mid)change1(ql,qr,x,l,mid,p<<1);
if(qr>mid){
int t=max(ql,mid+1);
change1(ql,qr,x*pw2[t-s]%P,mid+1,r,p<<1|1);
}
sum[p]=norm(sum[p<<1]+sum[p<<1|1]);
}
}
void change2(int ql,int qr,ll x,int l,int r,int p){
if(ql<=l&&r<=qr){
set_lazy(p,0,0,0,x,r-l+1);
}
else{
int mid=(l+r)>>1;
down(p,mid-l+1,r-mid);
int t=min(qr,r);
if(ql<=mid){
int s=min(qr,mid);
change2(ql,qr,x*pw2[t-s]%P,l,mid,p<<1);
}
if(qr>mid)change2(ql,qr,x,mid+1,r,p<<1|1);
sum[p]=norm(sum[p<<1]+sum[p<<1|1]);
}
}
int get_lca(int u,int v){
while(top[u]!=top[v]){
if(dep[top[u]]>dep[top[v]])u=fa[top[u]];
else v=fa[top[v]];
}
return dep[u]>dep[v]?v:u;
}
void solve1(int u,int v,int op,ll x,ll d){
int lca=get_lca(u,v),cnt=0;
int tot=dep[u]+dep[v]-2*dep[lca]+1;
while(top[u]!=top[lca]){
int l=dfn[top[u]],r=dfn[u],len=r-l+1;
if(op==1)add(l,r,norm(x+1LL*(cnt+len-1)*d),norm(-d),1,n,1);
else if(op==2)mul2(l,r,x*pw2[cnt]%P,1,n,1);
else if(op==3)change(l,r,norm(x+1LL*(cnt+len-1)*d),norm(-d),1,n,1);
else change2(l,r,x*pw2[cnt]%P,1,n,1);
cnt+=len;
u=fa[top[u]];
}
if(dep[u]>=dep[lca]){
int l=dfn[lca],r=dfn[u],len=r-l+1;
if(op==1)add(l,r,norm(x+1LL*(cnt+len-1)*d),norm(-d),1,n,1);
else if(op==2)mul2(l,r,x*pw2[cnt]%P,1,n,1);
else if(op==3)change(l,r,norm(x+1LL*(cnt+len-1)*d),norm(-d),1,n,1);
else change2(l,r,x*pw2[cnt]%P,1,n,1);
cnt+=len;
}
while(top[v]!=top[lca]){
int l=dfn[top[v]],r=dfn[v],len=r-l+1;
tot-=len;
if(op==1)add(l,r,norm(x+1LL*tot*d),d,1,n,1);
else if(op==2)mul1(l,r,x*pw2[tot]%P,1,n,1);
else if(op==3)change(l,r,norm(x+1LL*tot*d),d,1,n,1);
else change1(l,r,x*pw2[tot]%P,1,n,1);
v=fa[top[v]];
}
if(v!=lca){
int l=dfn[lca]+1,r=dfn[v],len=r-l+1;
tot-=len;
if(op==1)add(l,r,norm(x+1LL*tot*d),d,1,n,1);
else if(op==2)mul1(l,r,x*pw2[tot]%P,1,n,1);
else if(op==3)change(l,r,norm(x+1LL*tot*d),d,1,n,1);
else change1(l,r,x*pw2[tot]%P,1,n,1);
}
}
ll query(int ql,int qr,int l,int r,int p){
if(ql<=l&&r<=qr)return sum[p];
int mid=(l+r)>>1;
down(p,mid-l+1,r-mid);
ll ans=0;
if(ql<=mid)ans+=query(ql,qr,l,mid,p<<1);
if(qr>mid)ans+=query(ql,qr,mid+1,r,p<<1|1);
return norm(ans);
}
ll query_path(int u,int v){
int lca=get_lca(u,v);
ll ans=0;
while(top[u]!=top[lca]){
ans=norm(ans+query(dfn[top[u]],dfn[u],1,n,1));
u=fa[top[u]];
}
ans=norm(ans+query(dfn[lca],dfn[u],1,n,1));
while(top[v]!=top[lca]){
ans=norm(ans+query(dfn[top[v]],dfn[v],1,n,1));
v=fa[top[v]];
}
if(v!=lca)ans=norm(ans+query(dfn[lca]+1,dfn[v],1,n,1));
return ans;
}
int main(){
n=read(),q=read(),P=read();
for(int i=1;i<n;i++){
int u=read(),v=read();
G[u].push_back(v);
G[v].push_back(u);
}
for(int i=1;i<=n;i++)a[i]=norm(read());
dfs1(1,0);
dfs2(1,0,1);
pw2[0]=1%P;
for(int i=1;i<=n;i++)pw2[i]=pw2[i-1]*2%P;
build(1,n,1);
while(q--){
int op=read(),u=read(),v=read();
if(op==5)cout<<query_path(u,v)<<'\n';
else if(op==1||op==3){
ll x=norm(read()),d=norm(read());
solve1(u,v,op,x,d);
}
else{
ll x=norm(read());
solve1(u,v,op,x,0);
}
}
return 0;
}

浙公网安备 33010602011771号