zoukankan      html  css  js  c++  java
  • 「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
    ",an.ask(hd));
    		else ++hd,in(l),in(r),an.add(l,r);
    	}
    	return 0;
    }
    
  • 相关阅读:
    SLAM+语音机器人DIY系列:(二)ROS入门——3.在ubuntu16.04中安装ROS kinetic
    SLAM+语音机器人DIY系列:(二)ROS入门——2.ROS系统整体架构
    2017年 年计划
    125. Valid Palindrome
    一道多树递归面试题
    顺序表查找和有序表查找
    c++中常见概念、关键字等的区别
    两个栈实现一个队列,两个队列实现一个栈
    150. Evaluate Reverse Polish Notation
    堆排序
  • 原文地址:https://www.cnblogs.com/klauralee/p/10856043.html
Copyright © 2011-2022 走看看