「ZJOI2019」线段树

「ZJOI2019」线段树

这么多棵线段树显然是要合并在一起算的...

线段树每个节点记该点有标记的概率\(v_i\),总的答案就是\(\sum v_i*2^t\)

对于某一次操作:\([ql,qr]\),分情况考虑。

  1. 某个节点\([l,r] ,ql \leq l \leq r \leq qr\),显然修改后tag=1,那么\(\displaystyle v={(v+1) \over 2}\)

  2. 某个节点\([l,r]\)\([ql,qr]\)有交,显然修改后tag=0,那么\(\displaystyle v={v \over 2}\)

  3. 某个节点是2类点的儿子,且不是1,2类点,这时候该节点是否有tag取决于它到根的路径上是否有节点有tag标记。

  4. 某节点不属于1,2,3类点,那么\(v\)不变。

考虑对每个节点再维护 它到根的路径上有节点有tag标记 的概率\(val_i\)

此时3类点\(\displaystyle v={(v+val) \over 2}\),因此维护\(v\)一次复杂度\(o(log(n))\)

维护\(val\)依旧分情况考虑(每类点定义同上)。

  1. 对于该点的子树\(\displaystyle val={val+1 \over 2}\)

  2. 对于该点\(\displaystyle val={val \over 2}\)

2类点修改复杂度\(o(log(n))\),1类点可以打lazy标记(一个点被修改\(i\)次,\(\displaystyle val ={val+2^i-1 \over 2^i}\))。

然后就可以啦。

省选的时候智力--,感觉再这样下去没救了...

#include<bits/stdc++.h>
#define rep(q,a,b) for(int q=a,q##_end_=b;q<=q##_end_;++q)
#define dep(q,a,b) for(int q=a,q##_end_=b;q>=q##_end_;--q)
#define mem(a,b) memset(a,b,sizeof a )
#define debug(a) cerr<<#a<<' '<<a<<"___"<<endl
using namespace std;
void in(int &r) {
	static char c;
	r=0;
	while(c=getchar(),c<48);
	do r=(r<<1)+(r<<3)+(c^48);
	while(c=getchar(),c>47);
}
const int mod=998244353;
const int inv_2=499122177;
const int mn=100005;
int n,m,mul[mn],inv[mn];
struct segment_tree{
	int addv[mn<<2],v[mn<<2],val[mn<<2],y_1,y_2,tot;
	void push_down(int o){
		if(addv[o]){
			if(o <= n<<1){
				addv[o<<1]+=addv[o];
				addv[o<<1|1]+=addv[o];
			}
			val[o]=1LL*(val[o]+mul[addv[o]]-1)*inv[addv[o]]%mod;
			addv[o]=0;
		}
	}
	void add(int o,int l,int r){
		if(l>r)return;
		tot-=v[o];
		if(y_1<=l&&r<=y_2){
			v[o]=1LL*(v[o]+1)*inv_2%mod;
			tot+=v[o],tot%=mod;
			++addv[o];
		}else{
			push_down(o);
			if(l>y_2||r<y_1){
				v[o]=1LL*(v[o]+val[o])*inv_2%mod;
				tot+=v[o],tot%=mod;
			}else{
				v[o]=1LL*v[o]*inv_2%mod;
				val[o]=1LL*val[o]*inv_2%mod;
				tot+=v[o],tot%=mod;
				int mid=l+r>>1;
				add(o<<1,l,mid);
				add(o<<1|1,mid+1,r);
			}
		}
	}
	void add(int l,int r){
		y_1=l,y_2=r;
		add(1,1,n);
	}
	int ask(int hd){
		tot=(tot+mod)%mod;
		return 1LL*mul[hd]*tot%mod;
	}
}an;
int main(){
	freopen("segment.in","r",stdin);
	freopen("segment.out","w",stdout);
	in(n),in(m);
	mul[0]=1;
	rep(q,1,m)mul[q]=mul[q-1]*2%mod;
	inv[0]=1;
	rep(q,1,m)inv[q]=1LL*inv[q-1]*inv_2%mod;
	int ty,l,r,hd=0;
	while(m--){
		in(ty);
		if(ty==2)printf("%d\n",an.ask(hd));
		else ++hd,in(l),in(r),an.add(l,r);
	}
	return 0;
}
posted @ 2019-05-13 13:01  Eeis  阅读(171)  评论(0编辑  收藏  举报