P12488 题解
DaiRuiChen007 · · 题解
Problem Link
题目大意
给定长度为
n 的环,在第i 个点有1-p_i 的概率停止,否则走到(i+d)\bmod n 。初始给定
p'_0\sim p'_{m-1} ,p_i=p'_{i\bmod m} ,然后给出一棵树,q 个叶子,每个叶子表示对p 的单点修改(修改的位置不同)。对每个节点,求出进行其子树内所有叶子代表的修改后,随机从一个点出发后期望走多少步停止(开始算一步)。
数据范围:
n\le 10^{16},m\le 5000,q\le 10^5 ,\gcd(n,d)=1 。
思路分析
从
那么解
如果
那么
然后维护子树内所有操作,启发式合并比较简单,但更优的做法是线段树合并,即两棵子树中有一棵被修改过,另一棵则是原树上节点,就返回修改过的一棵,复杂度不变。
这样就在
然后回到原问题,把
先考虑
那么我们可以看成
两个取模太困难了,写成
考察直线
那么维护初始
然后考虑如何建立线段树结构。
注意到万欧过程中维护
由于万欧只有
时间复杂度
代码呈现
#include<bits/stdc++.h>
#define ll long long
#define LL __int128
using namespace std;
const int MAXN=1e5+5,MOD=998244353,MAXS=2e7+5;
ll ksm(ll a,ll b=MOD-2) { ll s=1; for(;b;a=a*a%MOD,b>>=1) if(b&1) s=s*a%MOD; return s; }
struct func {
ll a,b,c,d; //f=ax+b, s=cx+d
inline friend func operator +(const func &l,const func &r) {
return {l.a*r.a%MOD,(l.b+l.a*r.b)%MOD,(l.c*r.a+r.c)%MOD,(l.d+r.d+l.c*r.b)%MOD};
}
ll val() { return (b*ksm(1+MOD-a)%MOD*c+d)%MOD; }
};
func f[MAXS];
ll n,d,siz[MAXS];
int m,q1,q2,ls[MAXS],rs[MAXS],tot;
int comb(int x,int y) {
if(!x||!y) return x|y;
++tot,ls[tot]=x,rs[tot]=y;
siz[tot]=siz[x]+siz[y],f[tot]=f[x]+f[y];
return tot;
}
struct info {
int d,f[5005];
info() { d=0,memset(f,0,sizeof(f)); }
inline friend info operator *(const info &u,const info &v) {
info w; w.d=(u.d+v.d)%m;
for(int i=0;i<m;++i) w.f[i]=comb(u.f[i],v.f[(i+u.d)%m]);
return w;
}
};
info ksm(info a,ll b) { info s; for(;b;a=a*a,b>>=1) if(b&1) s=s*a; return s; }
info euclid(ll N,ll P,ll Q,ll R,info X,info Y) {
if((LL)P*N+R<Q) return ksm(Y,N);
if(P>=Q) return euclid(N,P%Q,Q,R,X,ksm(X,P/Q)*Y);
ll M=((LL)P*N+R)/Q;
return ksm(Y,(Q-R-1)/P)*X*euclid(M-1,Q,P,(Q-R-1)%P,Y,X)*ksm(Y,N-((LL)Q*M-R-1)/P);
}
int rt[MAXN*2],lim;
void upd(ll x,int z,int q,int &p) {
siz[p=++tot]=siz[q];
if(siz[p]==1) return f[p]={z,1,z,1},void();
if(x<=siz[ls[q]]) upd(x,z,ls[q],ls[p]),rs[p]=rs[q];
else upd(x-siz[ls[q]],z,rs[q],rs[p]),ls[p]=ls[q];
f[p]=f[ls[p]]+f[rs[p]];
}
int merge(int p,int q) {
if(p<=lim||q<=lim) return max(p,q);
ls[p]=merge(ls[p],ls[q]),rs[p]=merge(rs[p],rs[q]);
f[p]=f[ls[p]]+f[rs[p]];
return p;
}
void exgcd(ll a,ll b,ll &x,ll &y) {
if(!b) x=1,y=0;
else exgcd(b,a%b,y,x),y-=x*(a/b);
}
ll inv(ll u,ll p){
ll a,b; exgcd(u,p,a,b);
return (a%p+p)%p;
}
signed main() {
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin>>n>>m>>d>>q1>>q2;
for(int i=1,x;i<=m;++i) cin>>x,f[i]={x,1,x,1},siz[i]=1;
info X,Y,Z;
X.d=(m-n%m)%m,Y.d=d%m,tot=m;
for(int i=0;i<m;++i) Y.f[i]=i+1;
rt[0]=euclid(n,d,n,0,X,Y).f[d%m];
cout<<f[rt[0]].val()<<"\n",lim=tot;
ll iv=inv(d,n);
for(int i=1;i<=q1;++i) {
ll x,y; cin>>x>>y,x=(LL)x*iv%n;
upd(x?x:n,y,rt[0],rt[i]);
cout<<f[rt[i]].val()<<"\n";
}
for(int i=q1+1,x,y;i<=q1+q2;++i) {
cin>>x>>y;
rt[i]=merge(rt[x],rt[y]);
cout<<f[rt[i]].val()<<"\n";
}
return 0;
}