【LOJ#3043】【洛谷P5280】【ZJOI2019】—线段树(计数dp+线段树)

LOJ传送门

洛谷传送门

早上在知乎看到吉司机说这是一道期望+数据结构
一脸懵逼

原来就是把计数看成期望乘上情况


分析一波复制操作
就可以发现其实就是求每次操作有//没有的2t2^t种情况的tagtag之和

如果按照线段树这个样子
似乎……可以直接用线段树维护?
维护一个tr[u]tr[u]表示线段树上点uu当前有多少种情况为11

没有影响到的点显然tagtag是不会改变的的,也就是trtr乘2

对于所有线段树遍历而且非修改的点,他们的tagtag显然都被变成00
所以这些点trtr不变

对于所有直接修改到的节点显然无论前面情况怎么样现在的tagtag都为1
也就是加上2t2^t

发现pushdownpushdown还会影响所有修改节点的兄弟
但是只有当原来父亲以上有tagtag为1的时候这里才会变成1
再维护一个f[u]f[u]表示有多少种情况f[u]f[u]到根会有点tagtag为1
trtr直接加上ff就是了

那考虑ff怎么维护
对于不被修改的点,tagtag不变,ff乘2

修改路径上的点,tagtag变成了0,ff不变

被修改的点,tagtag变成了11ff加上2t2^t

所有兄弟,tagtag变成了11ff乘2

又发现所有不被修改的点都是兄弟的儿子
所以就只用讨论3种情况了

修改路径上的点:trtr不变,ff不变

被修改的点:tr+=2ttr+=2^t,子树所有f+=2tf+=2^t

兄弟节点:子树所有tr+=ftr+=f,子树所有f=f2f=f*2

#include<bits/stdc++.h>
using namespace std;
const int RLEN=1<<20|1;
inline char gc(){
	static char ibuf[RLEN],*ib,*ob;
	(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ib==ob)?EOF:*ib++;
}
inline int read(){
	char ch=gc();
	int res=0,f=1;
	while(!isdigit(ch))f^=ch=='-',ch=gc();
	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
	return f?res:-res;
}
const int N=100005;
const int mod=998244353;
inline int add(int a,int b){
	return a+b>=mod?a+b-mod:a+b;
}
inline int mul(int a,int b){
	return 1ll*a*b>=mod?1ll*a*b%mod:a*b;
}
inline void dec(int &a,int b){
	a=a>=b?a-b:a-b+mod;
}
inline void selfadd(int &a,int b){
	a=add(a,b);
}
inline void selfmul(int &a,int b){
	a=mul(a,b);
}
int ans,t,n,m,res;
namespace Seg{
	int tr[N<<2],f[N<<2],mulf[N<<2],addf[N<<2],mul[N<<2];
	#define lc (u<<1)
	#define rc ((u<<1)|1)
	#define mid ((l+r)>>1)
	inline void build(int u,int l,int r){
		mulf[u]=mul[u]=1;
		if(l==r)return;
		build(lc,l,mid),build(rc,mid+1,r);
	}
	inline void pushmulf(int u,int k){
		selfmul(addf[u],k),selfmul(f[u],k),selfmul(mulf[u],k);
	}
	inline void pushadd(int u,int k){
		selfadd(f[u],k),selfadd(addf[u],k);
	}
	inline void pushmul(int u,int k){
		selfmul(mul[u],k),selfmul(tr[u],k);
	}
	inline void pushdown(int u){
		if(mulf[u])pushmulf(lc,mulf[u]),pushmulf(rc,mulf[u]),mulf[u]=1;
		if(addf[u])pushadd(lc,addf[u]),pushadd(rc,addf[u]),addf[u]=0;
		if(mul[u])pushmul(lc,mul[u]),pushmul(rc,mul[u]),mul[u]=1;
	}
	void update(int u,int l,int r,int st,int des){
		if(st<=l&&r<=des){
			dec(ans,tr[u]);
			selfadd(tr[u],t),pushadd(u,t),selfmul(mul[u],2);
			selfadd(res,tr[u]);
			return;
		}
		if(r<st||des<l){
			dec(ans,tr[u]);
			selfadd(tr[u],f[u]),selfmul(mul[u],2),pushmulf(u,2);
			selfadd(res,tr[u]);
			return;
		}
		pushdown(u);
		dec(ans,tr[u]),selfadd(res,tr[u]);
		update(lc,l,mid,st,des);
		update(rc,mid+1,r,st,des);
	}
}
using namespace Seg;
int main(){
	n=read(),m=read();
	build(1,1,n);t=1;
	for(int i=1;i<=m;i++){
		int op=read();
		if(op==1){
			int l=read(),r=read();
			res=0;
			update(1,1,n,l,r);
			selfmul(t,2);
			selfmul(ans,2);
			selfadd(ans,res);
		}
		else cout<<ans<<'\n';
	}
}
posted @ 2019-04-06 15:41  Stargazer_cykoi  阅读(129)  评论(0编辑  收藏  举报