[ZJOI2017]树状数组
就贴一个\(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\)的概率
显然对于\(i\in[l,r]\),有这样的转移
发现我们可以把转移写成矩阵的形式
这样我们就可以使用数据结构来维护矩阵乘法了
这样这道题就做完了吗?
显然不是
发现如果有两个位置\(i,j\in[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\n",p1.a[1][1]);
else printf("%d\n",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\n",(f[0]*g[1]%mod+f[1]*g[0]%mod)%mod);
}
}
return 0;
}
upd
发现正解好简单,我真是一个思博,活该被卡