雾
那么对于每个询问,如果l!=1,那么我们查询的其实是[l−1,r−1]这段区间。而[l−1,r−1]与[l,r]仅有l−1和r这两个元素有区别。所以我们每次询问就是问l−1和r
的修改次数在模2意义下是否相等。
那么我们可以把每个询问看成(l−1,r)
这个点,那么这就是个二维选点问题了,我们用树套树来维护。外层的树维护第一维坐标,内层的树维护第二维坐标。我们维护的值就是这个点的两个坐标修改次数在模2意义下相等的概率。
如何合并概率呢?当两个点被修改的概率分别为p1,p2时,两个点修改次数相等的概率是p=p1∗p2+(1−p1)∗(1−p2),这个式子也适用于合并操作。
当l=1时,情况类似,我们要求的就变成了对于r这个点,它的前缀和是否与它的后缀和相等。维护思想与l!=1的情况类似。
使用标记永久化进行维护
Luogu 3688
#include
#include
#include
#include
#define merge(p1,p2) ((p1*p2+(1-p1+mod)*(1-p2+mod))%mod)
#define int long long
const int mod=998244353;
const int maxm=100010;
int rt[maxm*4];
int n,m;
int ans;
namespace inside_seg{
int ls[maxm*210],rs[maxm*210];
int sum[maxm*210];
int sz;
void modify(int &now,int l,int r,int ql,int qr,int v)
{
if(!now) sum[now=++sz]=1;
if(ql<=l&&r<=qr)
{
sum[now]=merge(sum[now],v);
return;
}
int mid=(l+r)>>1;
if(ql<=mid) modify(ls[now],l,mid,ql,qr,v);
if(qr>mid) modify(rs[now],mid+1,r,ql,qr,v);
}
void ask(int now,int l,int r,int ind)
{
if(!now) return;
ans=merge(ans,sum[now]);
if(l>=r) return;
int mid=(l+r)>>1;
if(ind<=mid) ask(ls[now],l,mid,ind);
else ask(rs[now],mid+1,r,ind);
}
}
namespace external_seg{
void modify(int now,int l,int r,int l1,int r1,int l2,int r2,int v)
{
if(l1<=l&&r<=r1)
{
inside_seg::modify(rt[now],0,n+1,l2,r2,v);
return;
}
int mid=(l+r)>>1;
if(l1<=mid) modify((now<<1),l,mid,l1,r1,l2,r2,v);
if(r1>mid) modify((now<<1)|1,mid+1,r,l1,r1,l2,r2,v);
}
void ask(int now,int l,int r,int ind1,int ind2)
{
if(rt[now]) inside_seg::ask(rt[now],0,n+1,ind2);
if(l>=r) return;
int mid=(l+r)>>1;
if(ind1<=mid) ask((now<<1),l,mid,ind1,ind2);
else ask((now<<1)|1,mid+1,r,ind1,ind2);
}
}
int fastpow(int x,int y)
{
x%=mod;
int ans=1;
while(y)
{
if(y%2) ans=(ans*x)%mod;
x=(x*x)%mod;
y/=2;
}
return ans%mod;
}
main()
{
//freopen("233.out","w",stdout);
scanf("%lld%lld",&n,&m);
for(int i=1;i<=m;i++)
{
int opt,l,r;
scanf("%lld%lld%lld",&opt,&l,&r);
if(opt==1)
{
int p=fastpow(r-l+1,mod-2);
if(l>1) external_seg::modify(1,0,n,1,l-1,l,r,(1-p+mod)%mod);
if(r1,0,n,l,r,r+1,n,(1-p+mod)%mod);
int pp=p<<1;
if(pp>=mod) pp-=mod;
external_seg::modify(1,0,n,l,r,l,r,(1-pp+mod)%mod);
external_seg::modify(1,0,n,0,0,0,l-1,0);
external_seg::modify(1,0,n,0,0,r+1,n+1,0);
external_seg::modify(1,0,n,0,0,l,r,p);
}
else
{
ans=1;
external_seg::ask(1,0,n,l-1,r);
printf("%lld\n",ans%mod);
}
}
return 0;
}