zoukankan      html  css  js  c++  java
  • 雅礼培训 Problem A 【线段树】

    题意##

    维护一段区间,支持求区间最大值,区间且,区间或
    (n,q<=2*10^5)

    题解##

    我们用线段树维护区间最大值

    对于and和or运算,
    and实质就是强行把一些位改为0
    or实质就是强行把一些位改为1

    那么由线段树区间标记的思想,如果某个操作对整个区间的影响是相同的,并且能很快维护出当前节点信息,我们就可以通过打标记进行优化
    显然,当需要操作的那些位在整个区间都是相同的,我们就可以打上一个标记

    对于统计区间相同位置,有一个小技巧:
    维护区间or和区间and
    and中为1的位区间都为1
    or中为0的位区间都为0
    二者整合起来就可以得到区间相同的位置集合

    复杂度##

    如果区间总是不相同,复杂度会不会变差呢?
    很显然,每次操作只能使所有位置相同的越来越多,而原来不同的位置经操作后一定变为相同
    所以复杂度依旧是(O(nlogn))

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define LL long long int
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define Redge(u) for (int k = h[u]; k; k = ed[k].nxt)
    #define ls (u << 1)
    #define rs (u << 1 | 1)
    using namespace std;
    const int maxn = 200005,maxm = 100005,maxv = (1 << 20) - 1,INF = 1000000000;
    inline int read(){
    	int out = 0,flag = 1; char c = getchar();
    	while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
    	while (c >= 48 && c <= 57) {out = (out << 1) + (out << 3) + c - '0'; c = getchar();}
    	return out * flag;
    }
    int mx[4 * maxn],And[4 * maxn],Or[4 * maxn];
    int vand[4 * maxn],vor[4 * maxn];
    int n,A[maxn],Q;
    void work_and(int u,int v){
    	mx[u] &= v; And[u] &= v; Or[u] &= v;
    	vand[u] &= v; vor[u] &= v;
    }
    void work_or(int u,int v){
    	mx[u] |= v; And[u] |= v; Or[u] |= v;
    	vand[u] |= v; vor[u] |= v;
    }
    void upd(int u){
    	vand[u] = vand[ls] & vand[rs];
    	vor[u] = vor[ls] | vor[rs];
    	mx[u] = max(mx[ls],mx[rs]);
    }
    void pd(int u){
    	if (And[u] != maxv){
    		work_and(ls,And[u]);
    		work_and(rs,And[u]);
    		And[u] = maxv;
    	}
    	if (Or[u]){
    		work_or(ls,Or[u]);
    		work_or(rs,Or[u]);
    		Or[u] = 0;
    	}
    }
    void build(int u,int l,int r){
    	And[u] = maxv;
    	Or[u] = 0;
    	if (l == r){
    		mx[u] = vand[u] = vor[u] = A[l];
    		return;
    	}
    	int mid = l + r >> 1;
    	build(ls,l,mid);
    	build(rs,mid + 1,r);
    	upd(u);
    }
    void modify(int u,int l,int r,int L,int R,int v,int opt){
    	if (l >= L && r <= R){
    		if (opt == 1){
    			if (((v ^ maxv) & ((vor[u] ^ maxv) | vand[u])) == (v ^ maxv)){
    				work_and(u,v);
    				return;
    			}
    		}
    		else {
    			if ((v & ((vor[u] ^ maxv) | vand[u])) == v){
    				work_or(u,v);
    				return;
    			}
    		}
    	}
    	pd(u);
    	int mid = l + r >> 1;
    	if (mid >= L) modify(ls,l,mid,L,R,v,opt);
    	if (mid < R) modify(rs,mid + 1,r,L,R,v,opt);
    	upd(u);
    }
    int query(int u,int l,int r,int L,int R){
    	if (l >= L && r <= R) return mx[u];
    	pd(u);
    	int mid = l + r >> 1;
    	if (mid >= R) return query(ls,l,mid,L,R);
    	else if (mid < L) return query(rs,mid + 1,r,L,R);
    	else return max(query(ls,l,mid,L,R),query(rs,mid + 1,r,L,R));
    }
    int main(){
    	n = read(); Q = read();
    	for (int i = 1; i <= n; i++) A[i] = read();
    	build(1,1,n);
    	int opt,l,r;
    	while (Q--){
    		opt = read();
    		l = read();
    		r = read();
    		if (opt < 3) modify(1,1,n,l,r,read(),opt);
    		else printf("%d
    ",query(1,1,n,l,r));
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    Entity Framework Core系列教程-1-介绍
    火锅大队作品简介
    一号课题组作品简介
    Attract队作品简介
    华理时空之眼队作品简介
    热情致终队作品简介
    触摸阳光队作品简介
    PIE SDK水体指数法
    PIE SDK水深提取算法
    PIE SDK直方图统计法
  • 原文地址:https://www.cnblogs.com/Mychael/p/8696359.html
Copyright © 2011-2022 走看看