就贴一个(loj)的链接吧,因为也就只有(loj)能过
发现可怜的树状数组写反了,那么根据经验可怜求得其实就是后缀和
发现都是在二进制下进行的操作,于是那个减法和加法没有什么区别,我们可以看成是后缀(l-1)的和减掉后缀(r)的和
就是
发现求得就是([l-1,r-1])这段区间的和
我们考虑一下这一段区间和([l,r])的差别
发现([l-1,r-1]-a_{l-1}+a_r=[l,r])
所以如果(a_r=a_{l-1}),我们就会发现这两段区间区间和是相等的
现在我们的问题就变成了求(a_{l-1})和(a_r)相等的概率了
设(dp_{i,0/1})表示(i)位置是(0/1)的概率
显然对于(iin[l,r]),有这样的转移
发现我们可以把转移写成矩阵的形式
这样我们就可以使用数据结构来维护矩阵乘法了
这样这道题就做完了吗?
显然不是
发现如果有两个位置(i,jin[l,r]),我们会把这两个位置都修改一遍,如果再查询这两个位置是否相等的话,我们就相当于在([l,r])这个区间选择了两个数加(1)
这一点也不科学啊
我们考虑一段区间同时包含了我们当前的两个询问点(i,j)
有(frac{2}{r-l+1})的概率使得其中一个被加(1),(frac{r-l-1}{r-l+1})的概率加到了某一个没有什么影响的数上面去了
如果一个数加(1),那么我们的判断条件就从两个数相同变成了两个数不同,也就是要求发生改变
于是我们再来一个(f_{0/1})表示当前的要求是两个数不同/相同的概率
这里也有一个矩阵
对于(i,j)询问的答案就应该是
于是我们需要处理出所有的包含(i)不包含(j),包含(j)不包含(i)的区间的矩阵乘积,求出(dp_{i,0},dp_{i,1},dp_{j,0},dp_{j,1})
以及所有包含(i)又包含(j)的区间的矩阵乘积,求出(f_0,f_1)
发现这是一个二维的关系,我们可以直接上树套树
看起来就解决了
但是还是没有完,我们认真读题会发现在(l-1=0)的时候给出的代码特判退出了
那么我们就没有办法求(a_{l-1}=a_r)的概率了,发现这个时候可怜求得其实是(r)的后缀和
现在我们的问题变成了判断(r)的前缀和等于后缀和的概率
注意到这个前缀和后缀有一个公共点是(r),也就是(r)被修改是没有什么影响的
我们来一个树状数组,求出([1,r-1])和([r+1,n])这两段的和
求得就是有多少段区间被([1,r-1])和([r+1,n])完全包含,这些区间无论如何随机都一定能让这段区间的和加(1)
之后对于那些跨过(r)的区间,我们有(frac{1}{len})的概率选中(r)这个位置使得没什么影响,(frac{len-1}{len})的概率选在前缀和后缀中
我们还是可以写成矩阵来进行转移,于是还是需要一个树套树来维护
现在终于做完了,但还是二维线段树的空间太大了实在开不过去了
仅仅能在(loj)上过的代码
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define re register
#define LL long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
const int maxn=1e5+5;
const int M=2e7+10;
const LL mod=998244353;
inline int read() {
char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
void exgcd(LL a,LL b,LL &x,LL &y) {if(!b) {x=1,y=0;return;}exgcd(b,a%b,y,x);y-=a/b*x;}
inline LL getInv(LL a) {LL x,y;exgcd(a,mod,x,y);return (x%mod+mod)%mod;}
struct mat{int a[2][2];};
inline mat operator*(mat a,mat b) {
mat c;
c.a[0][0]=((LL)a.a[0][0]*(LL)b.a[0][0]%mod+(LL)a.a[0][1]*(LL)b.a[1][0]%mod)%mod;
c.a[0][1]=((LL)a.a[0][0]*(LL)b.a[0][1]%mod+(LL)a.a[0][1]*(LL)b.a[1][1]%mod)%mod;
c.a[1][0]=((LL)a.a[1][0]*(LL)b.a[0][0]%mod+(LL)a.a[1][1]*(LL)b.a[1][0]%mod)%mod;
c.a[1][1]=((LL)a.a[1][0]*(LL)b.a[0][1]%mod+(LL)a.a[1][1]*(LL)b.a[1][1]%mod)%mod;
return c;
}
int n,m,cnt;
LL dp[2][2],f[2],g[2];
int ls[maxn<<2],rs[maxn<<2],pos[maxn];
void build(int x,int y,int i) {
ls[i]=x,rs[i]=y;
if(x==y) {pos[x]=i;return;}
int mid=x+y>>1;
build(x,mid,i<<1);build(mid+1,y,i<<1|1);
}
int l[M],r[M];mat d[M];
int add(int now,int pos,int x,int y,mat v) {
if(!now) {
now=++cnt;
d[now].a[0][0]=d[now].a[1][1]=1;
}
d[now]=d[now]*v;
if(x==y) return now;
int mid=x+y>>1;
if(pos<=mid) l[now]=add(l[now],pos,x,mid,v);
else r[now]=add(r[now],pos,mid+1,y,v);
return now;
}
mat ask(int now,int x,int y,int lx,int ry) {
if(!now) return d[0];
if(x<=lx&&y>=ry) return d[now];
int mid=lx+ry>>1;
if(y<=mid) return ask(l[now],x,y,lx,mid);
if(x>mid) return ask(r[now],x,y,mid+1,ry);
return ask(l[now],x,y,lx,mid)*ask(r[now],x,y,mid+1,ry);
}
struct Segment_Tree {
int rt[maxn*3];
void change(int x,int y,mat v) {
int i=pos[x];
while(i)
rt[i]=add(rt[i],y,1,n,v),i>>=1;
}
mat query(int x,int y,int lx,int ry,int i) {
if(x<=ls[i]&&y>=rs[i]) return ask(rt[i],lx,ry,1,n);
int mid=ls[i]+rs[i]>>1;
if(y<=mid) return query(x,y,lx,ry,i<<1);
if(x>mid) return query(x,y,lx,ry,i<<1|1);
return query(x,y,lx,ry,i<<1)*query(x,y,lx,ry,i<<1|1);
}
}A,B,K;
struct Bit {
int c[maxn];
#define lb(x) (x&-x)
inline void add(int x) {
for(re int i=x;i<=n;i+=lb(i)) c[i]^=1;
}
inline int ask(int x) {
int now=0;
for(re int i=x;i;i-=lb(i)) now^=c[i];
return now;
}
}C,D;
int main() {
n=read(),m=read();
build(1,n,1);
d[0].a[0][0]=1;
d[0].a[1][1]=1;
int opt,x,y;
int h=0;
while(m--) {
opt=read(),x=read(),y=read();
if(opt==1) {
mat v;h^=1;
C.add(x),D.add(y);
LL len=y-x+1;
LL inv=getInv(len);
v.a[1][1]=v.a[0][0]=(len-1)*inv%mod;
v.a[0][1]=v.a[1][0]=inv;
A.change(x,y,v);
std::swap(v.a[0][0],v.a[0][1]);
std::swap(v.a[1][0],v.a[1][1]);
K.change(x,y,v);
if(x==y) continue;
v.a[1][1]=v.a[0][0]=(len-2)*inv%mod;
v.a[1][0]=v.a[0][1]=2ll*inv%mod;
B.change(x,y,v);
}
if(opt==2) {
x--;
mat p1,p2,p3;
if(!x) {
p1=K.query(1,y,y,n,1);
int o=D.ask(y-1),t=(h^C.ask(y));
if(o==t) printf("%d
",p1.a[1][1]);
else printf("%d
",p1.a[0][1]);
continue;
}
p1=A.query(1,x,x,y-1,1);
p2=A.query(x+1,y,y,n,1);
p3=B.query(1,x,y,n,1);
dp[0][0]=p1.a[0][1],dp[0][1]=p1.a[1][1];
dp[1][0]=p2.a[0][1],dp[1][1]=p2.a[1][1];
f[0]=p3.a[0][1],f[1]=p3.a[1][1];
g[0]=dp[0][0]*dp[1][0]%mod+dp[0][1]*dp[1][1]%mod;
g[0]%=mod;
g[1]=dp[0][1]*dp[1][0]%mod+dp[0][0]*dp[1][1]%mod;
g[1]%=mod;
printf("%lld
",(f[0]*g[1]%mod+f[1]*g[0]%mod)%mod);
}
}
return 0;
}
upd
发现正解好简单,我真是一个思博,活该被卡