• bzoj5312: 冒险(势能均摊线段树)


    题目链接

    BZOJ5312: 冒险

    题解

    如果一次操作对区间& 和 区间| 产生的影响是相同的,那么该操作对整个区间的影响都是相同的
    对于每次操作,在某些位上的值,对于整个区间影响是相同的,对相同影响的操作直接打标记
    否则递归子树
    复杂度证明:
    https://csacademy.com/contest/round-70/task/and-or-max/solution/

    代码

    #include<cstdio> 
    #include<algorithm> 
    inline int read() { 
    	int x = 0,f = 1; 
    	char c = getchar(); 
    	while(c < '0' || c > '9'){if(c == '-')f = -1; c = getchar(); } 
    	while(c <= '9' && c >= '0') x = x * 10 + c - '0',c = getchar(); 
    	return x *f ; 
    } const int maxn = 2000007; 
    int n,a[maxn],m; 
    int A[maxn << 1],O[maxn << 1],t[maxn << 1],tag[maxn]; 
    #define ls x << 1 
    #define rs x << 1 | 1
    inline void update(int x) { 
     	A[x] = A[ls] & A[rs];
        O[x] = O[ls] | O[rs];
    	t[x] = std::max(t[ls],t[rs]); 
    } 
    inline void ps(int x,int k ) { tag[x] += k; A[x] += k; O[x] += k; t[x] += k;	}  
    void pushdown(int x) { 
    	ps(ls,tag[x]); 
    	ps(rs,tag[x]); 
    	tag[x] = 0; 
    	return; 
    } 
    void build(int x,int l,int r) { 
    	if(l == r) { 
    		A[x] = O[x] = t[x] = a[l]; 
    		return ; 
    	}	 
    	int mid = l + r >> 1; 
    	build(x << 1,l,mid); build(x << 1 | 1,mid + 1,r); 
    	update(x); 
    } 
    void modify(int x,int l,int r,int L,int R,int k,int type) { 
    	bool t = false;   
    	if(type == 1) {  
    		if((O[x] & k) == O[x]) return; 
    		t = ((A[x] & k) - A[x] == (O[x] & k) - O[x]); 
    	} else { 
    		if((A[x] | k) == A[x]) return; 
    		t = ((A[x] | k) - A[x] == (O[x] | k) - O[x]); 
    	} 
    	if(l >= L && r <= R && t) { 
            if(type == 1) ps(x,(A[x] & k) - A[x]); 
    		else ps(x, (O[x] | k) - O[x]); 
    		return; 
    	} 
    	if(tag[x]) pushdown(x); 
    	int mid = l + r >> 1; 
    	if(L <= mid) modify(ls,l,mid,L,R,k,type); 
    	if(R > mid) modify(rs,mid + 1,r,L,R,k,type); 
    	update(x); 
    } 
    int query(int x,int l,int r,int L ,int R) { 
    	if(l >= L && r <= R) return t[x]; 
    	int ret = 0; 
    	if(tag[x]) pushdown(x); 
    	int mid = l + r >> 1; 
    	if(L <= mid) ret = std::max(ret,query(ls,l,mid,L,R)); 
    	if(R >  mid) ret = std::max(ret,query(rs,mid + 1,r,L,R)); 
    	return ret;  
    } 
    int main() { 
    	n = read(); m = read(); 
    	for(int i = 1;i <= n;++ i) a[i] = read(); 
    	build(1,1,n); 
    	for(int i = 1;i <= m;i += 1) { 
    		int type = read(),l = read(),r = read(); 
    		if(type == 1) { 
    			int x = read(); 
    			modify(1,1,n,l,r,x,type); 
    		} else if(type == 2) { 
    			int x = read(); 
    			modify(1,1,n,l,r,x,type); 
    		} else 
    			printf("%d
    ",query(1,1,n,l,r)); 
    	} 
    	return 0; 
    } 
    
  • 相关阅读:
    二叉树学习随笔
    结构体初始化中的数组赋值
    C和FORTRAN的快速傅里叶/余弦/正弦变换(Fast Fourier/Cosine/Sine Transform)开源库分享
    Java简单的数组用法尝试,和C语言很不一样
    中位数( 优先队列较优处理 )
    单调队列 数组写法qwq
    P1886 滑动窗口
    Sicily 2014. Dairy Queen
    P3385 【模板】负环
    [USACO06DEC]虫洞Wormholes (负环模板)
  • 原文地址:https://www.cnblogs.com/sssy/p/9645178.html
Copyright © 2020-2023  润新知