BZOJ4785 [Zjoi2017]树状数组

8 篇文章 0 订阅
2 篇文章 0 订阅

扯淡:

昨天就在BZOJ上看到了题,但是光老师说今天考ZJOI的题,就一直没看

看完题看了看部分分,所有修改在所有询问之前?那这题是不是肯定是cdq啊

然后YYYY,YY了一个贼JB恶心的CDQ,写了9000B,然后发现我们测的时候开4秒,觉得在校OJ上4秒肯定跑不过就交了70分暴力

后来考试结束了发现标程跑了3秒9……于是把时限开到8s,6s就过了

如果上天再给我一次机会,我一定写一个树套树,不知道好写到哪里去了,常数也小

做法:

首先可以发现这个树状数组其实求的是后缀和

然后嘛,如果询问的l不等于1,则相当于询问l-1和r相等的概率,如果l等于一,就相当于询问1~r-1的和与r+1到n的和相等的概率

l等于1和不等于1差不多,都是下面做法,但是要分开

那么考虑朴素做法,每次查询的时候枚举所有修改,计算一下影响即可

比如l等于1的情况,那么考虑比如修改的区间是l~r,查询的右端点在l~r之间

那么p会变成p/(r-l+1)+(1-p)*(r-l)/(r-l+1)

其他的情况类似考虑

发现一次修改的影响就相当于把概率乘一个数再加一个数

而把询问的左端点看成横坐标,右端点看成纵坐标,修改就相当于矩形乘加,拿cdq或者线段树维护即可

因为这题的特殊性质,所以不同的乘加之间顺序是无所谓的,所以cdq也是可行的

#include<iostream>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<cstdlib>
#include<cstdio>
#include<map>
#include<bitset>
#include<set>
#include<stack>
#include<vector>
#include<queue>
using namespace std;
#define MAXN 300010
#define MAXM 1010
#define ll long long
#define eps 1e-8
#define MOD 998244353
#define INF 1000000000
char xB[1<<15],*xS=xB,*xTT=xB;
#define getc() (xS==xTT&&(xTT=(xS=xB)+fread(xB,1,1<<15,stdin),xS==xTT)?0:*xS++)
#define isd(c) (c>='0'&&c<='9')
int read(){
	char xchh;
	int xaa;
    while(xchh=getc(),!isd(xchh));(xaa=xchh-'0');
    while(xchh=getc(),isd(xchh))xaa=xaa*10+xchh-'0';return xaa;
}
struct que{
	ll x;
	ll y;
	ll c;
	ll tim;
	ll A11,B11,A12,B12,A21,B21,A22,B22;
	ll nA11,nA12,nA21,nA22;
};
int n,m;
ll L[MAXN],R[MAXN];
ll ine[MAXN];
que a[MAXN];
que ta[MAXN];
int tot;
ll ans[MAXN];
ll ch[MAXN<<2],ad[MAXN<<2],col[MAXN<<2],flg[MAXN<<2];
bool qinding[MAXN];
ll frog[MAXN];
int son[MAXN<<2][2];
int TOT,rt;
bool FLAG;
bool cmpl(que x,que y){
	return x.x!=y.x?x.x<y.x:x.c>y.c;
}
void nn(int &x){
	if(!x){
		x=++TOT;
		ch[x]=1;
		ad[x]=0;
		col[x]=-1;
		flg[x]=0;
		son[x][0]=son[x][1]=0;
	}
}
ll mi(ll x,ll y){
	ll re=1;
	while(y){
		if(y&1){
			(re*=x)%=MOD;
		}
		(x*=x)%=MOD;
		y>>=1;
	}
	return re;
}
inline void tomul(int &x,ll y){
	nn(x);
	(ch[x]*=y)%=MOD;
	(ad[x]*=y)%=MOD;
}
inline void toad(int &x,ll y){
	nn(x);
	(ad[x]+=y)%=MOD;
}
inline void tocol(int &x,ll y){
	nn(x);
	col[x]=y;
}
inline void toch(int &x,ll y){
	nn(x);
	flg[x]+=y;
}
inline void pd(int &x){
	if(ch[x]!=1){
		tomul(son[x][0],ch[x]);
		tomul(son[x][1],ch[x]);
		ch[x]=1;
	}
	if(ad[x]){
		toad(son[x][0],ad[x]);
		toad(son[x][1],ad[x]);
		ad[x]=0;
	}
	if(col[x]!=-1){
		tocol(son[x][0],col[x]);
		tocol(son[x][1],col[x]);
		col[x]=-1;
	}
}
void change1(int &x,int y,int z,int l,int r,ll cv){
	
	if(l>r){
		return ;
	}
	nn(x);
	if(y==l&&z==r){
		tomul(x,cv);
		return ;
	}
	pd(x);
	int mid=y+z>>1;
	if(r<=mid){
		change1(son[x][0],y,mid,l,r,cv);
	}else if(l>mid){
		change1(son[x][1],mid+1,z,l,r,cv);
	}else{
		change1(son[x][0],y,mid,l,mid,cv);
		change1(son[x][1],mid+1,z,mid+1,r,cv);
	}
}
void change2(int &x,int y,int z,int l,int r,ll cv){
	if(l>r){
		return ;
	}
	nn(x);
	if(y==l&&z==r){
		toad(x,cv);
		return ;
	}
	pd(x);
	int mid=y+z>>1;
	if(r<=mid){
		change2(son[x][0],y,mid,l,r,cv);
	}else if(l>mid){
		change2(son[x][1],mid+1,z,l,r,cv);
	}else{
		change2(son[x][0],y,mid,l,mid,cv);
		change2(son[x][1],mid+1,z,mid+1,r,cv);
	}
}
void change3(int &x,int y,int z,int l,int r,ll cv){
	if(l>r){
		return ;
	}
	nn(x);
	if(y==l&&z==r){
		tocol(x,cv);
		return ;
	}
	pd(x);
	int mid=y+z>>1;
	if(r<=mid){
		change3(son[x][0],y,mid,l,r,cv);
	}else if(l>mid){
		change3(son[x][1],mid+1,z,l,r,cv);
	}else{
		change3(son[x][0],y,mid,l,mid,cv);
		change3(son[x][1],mid+1,z,mid+1,r,cv);
	}
}
void change4(int &x,int y,int z,int l,int r,ll cv){
	if(l>r){
		return ;
	}
	nn(x);
	if(y==l&&z==r){
		toch(x,cv);
		return ;
	}
	pd(x);
	int mid=y+z>>1;
	if(r<=mid){
		change4(son[x][0],y,mid,l,r,cv);
	}else if(l>mid){
		change4(son[x][1],mid+1,z,l,r,cv);
	}else{
		change4(son[x][0],y,mid,l,mid,cv);
		change4(son[x][1],mid+1,z,mid+1,r,cv);
	}
}
ll ask(int &x,int y,int z,int p,bool flag,ll X){
	nn(x);
	if(y==z){
		FLAG=flag||flg[x];
		return (flag||flg[x])?col[x]:(ch[x]*X%MOD+ad[x])%MOD;
	}
	int mid=y+z>>1;
	pd(x);
	if(p<=mid){
		return ask(son[x][0],y,mid,p,flag||flg[x],X);
	}else{
		return ask(son[x][1],mid+1,z,p,flag||flg[x],X);
	}
}
void cdq(int L,int R,int l,int r){
	if(L==R){
		return ;
	}
	int MID=L+R>>1;
	int i,j;
	int mid=l-1;
	for(i=l;i<=r;i++){
		if(a[i].tim<=MID){
			mid++;
		}
	}
	int tl=l,tr=mid+1;
	for(i=l;i<=r;i++){
		if(a[i].tim<=MID){
			ta[tl++]=a[i];
		}else{
			ta[tr++]=a[i];
		}
	}
	memcpy(a+l,ta+l,sizeof(que)*(r-l+1));
	cdq(L,MID,l,mid);
	rt=TOT=0;
	ll mul=1,ad=0;
	bool FLG=0,FLG2=0;
	for(i=l;i<=mid;i++){
		if(a[i].c==0||a[i].c==-1){
			FLG=1;
			break;
		}
	}
	for(i=mid+1;i<=r;i++){
		if(a[i].c==1||a[i].c==2){
			FLG2=1;
			break;
		}
	}
	if(FLG&&FLG2){
		for(i=l;i<=mid;i++){
			if(a[i].c==0){
				(mul*=a[i].A11)%=MOD;
				(ad*=a[i].A11)%=MOD;
				(ad+=a[i].B11)%=MOD;
				if(a[i].A22!=0){
					change1(rt,1,n,a[i].x,a[i].y,a[i].A22);
					change2(rt,1,n,a[i].x,a[i].y,a[i].B22);
				}else{
					change3(rt,1,n,a[i].x,a[i].y,a[i].B22);
					change4(rt,1,n,a[i].x,a[i].y,1);
				}
			}
		}
		int flag=0;
		ll ts;
		bool fro=1;
		for(i=l,j=mid+1;j<=r;j++){
			while(i<=mid&&a[i].x<=a[j].x){
				if(a[i].c==0){
					fro=0;
					(ad+=MOD-a[i].B11)%=MOD;
					(mul*=a[i].nA11)%=MOD;
					(ad*=a[i].nA11)%=MOD;
					if(a[i].A12==0){
						flag++;
						ts=a[i].B12;
					}else{
						(mul*=a[i].A12)%=MOD;
						(ad*=a[i].A12)%=MOD;
						(ad+=a[i].B12)%=MOD;
					}
					if(a[i].A22!=0){
						change2(rt,1,n,a[i].x,a[i].y,MOD-a[i].B22);
						change1(rt,1,n,a[i].x,a[i].y,a[i].nA22);
						change1(rt,1,n,a[i].y+1,n,a[i].A22);
						change2(rt,1,n,a[i].y+1,n,a[i].B22);
					}else{
						change4(rt,1,n,a[i].x,a[i].y,-1);
						change3(rt,1,n,a[i].y+1,n,a[i].B22);
						change4(rt,1,n,a[i].y+1,n,1);
					}
					if(a[i].A11!=0){
						change1(rt,1,n,a[i].x,a[i].y,a[i].A21);
						change2(rt,1,n,a[i].x,a[i].y,a[i].B21);
					}else{
						change3(rt,1,n,a[i].x,a[i].y,a[i].B21);
						change4(rt,1,n,a[i].x,a[i].y,1);
					}
				}
				if(a[i].c==-1){
					if(fro){
						i++;
						continue ;
					}
					if(a[i].nA12==0){
						flag--;
					}else{
						(ad+=MOD-a[i].B12)%=MOD;
						(mul*=a[i].nA12)%=MOD;
						(ad*=a[i].nA12)%=MOD;
					}
					(mul*=a[i].A11)%=MOD;
					(ad*=a[i].A11)%=MOD;
					(ad+=a[i].B11)%=MOD;
					//*
					swap(a[i].x,a[i].y);
					a[i].y--;
					//*/
					if(a[i].A22!=0){
						change2(rt,1,n,a[i].y+1,n,MOD-a[i].B22);
						change1(rt,1,n,a[i].y+1,n,a[i].nA22);
					}else{
						change4(rt,1,n,a[i].y+1,n,-1);
					}
					a[i].y++;
					swap(a[i].x,a[i].y);
				}
				i++;
			}
			if(a[j].c==1){
				fro=0;
				FLAG=0;
				ans[a[j].tim]=ask(rt,1,n,a[j].y,0,ans[a[j].tim]);
				if(FLAG){
					qinding[a[j].tim]=1;
					frog[a[j].tim]=ans[a[j].tim];
				}
			}
			if(a[j].c==2){
				fro=0;
				if(flag){
					qinding[a[j].tim]=1;
					frog[a[j].tim]=ts;
				}else{
					ans[a[j].tim]=(mul*ans[a[j].tim]+ad)%MOD;
				}
			}
		}
	}
	cdq(MID+1,R,mid+1,r);
	tl=l,tr=mid+1;
	for(i=l;i<=r;i++){
		if((cmpl(a[tl],a[tr])&&tl<=mid)||tr>r){
			ta[i]=a[tl++];
		}else{
			ta[i]=a[tr++];
		}
	}
	memcpy(a+l,ta+l,sizeof(que)*(r-l+1));
}
int main(){
	//*/
	memset(ans,-1,sizeof(ans));
	int i,j,o,x,y;
	ine[0]=ine[1]=1;
	for(i=2;i<MAXN;i++){
		ine[i]=(MOD-MOD/i)*ine[MOD%i]%MOD;
	}
	n=read();
	m=read();
	bool hhh=0;
	bool hhhh=1;
	for(i=1;i<=m;i++){
		o=read();
		if(o==1){
			tot++;
			a[tot].tim=i;
			a[tot].c=0;
			L[i]=read();
			R[i]=read();
			a[tot].x=L[i];
			a[tot].y=R[i];
			a[tot].A11=MOD-1;
			a[tot].B11=1;
			a[tot].A12=(L[i]-R[i]+1+MOD)*ine[R[i]-L[i]+1]%MOD;
			a[tot].B12=(R[i]-L[i])*ine[R[i]-L[i]+1]%MOD;
			a[tot].A21=(R[i]-L[i]-3+MOD)*ine[R[i]-L[i]+1]%MOD;
			a[tot].B21=2*ine[R[i]-L[i]+1]%MOD;
			a[tot].A22=(R[i]-L[i]-1+MOD)*ine[R[i]-L[i]+1]%MOD;
			a[tot].B22=ine[R[i]-L[i]+1];
			a[tot].nA11=mi(a[tot].A11,MOD-2);
			a[tot].nA12=mi(a[tot].A12,MOD-2);
			a[tot].nA21=mi(a[tot].A21,MOD-2);
			a[tot].nA22=mi(a[tot].A22,MOD-2);
			tot++;
			a[tot]=a[tot-1];
			a[tot].c=-1;
			swap(a[tot].x,a[tot].y);
			a[tot].x++;
		}
		if(o==2){
			hhh=1;
			tot++;
			a[tot].tim=i;
			a[tot].x=read();
			a[tot].y=read();
			if(a[tot].x==1){
				a[tot].x=a[tot].y;
				a[tot].c=2;
			}else{
				a[tot].x--;
				a[tot].c=1;
			}
			ans[i]=1;
		}
	}
	sort(a+1,a+tot+1,cmpl);
	cdq(1,m,1,tot);
	for(i=1;i<=tot;i++){
		if(ans[i]!=-1){
			if(qinding[i]){
				printf("%lld\n",frog[i]);
			}else{
				printf("%lld\n",ans[i]);
			}
		}
	}
	return 0;
}

/*
5 5
2 3 5
1 3 4
2 1 5
2 5 5
1 3 4




*/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值