zoukankan      html  css  js  c++  java
  • 「雅礼集训 2018 Day7」A

    题意:「雅礼集训 2018 Day7」A

    题解:
    线段树处理。
    考虑只有一种与的操作。显然当一个区间的或和与上将要与的数还是原数时就没必要递归计算了,剪枝剪掉。当一段区间与和与上将要与的数等于这段区间或和与上将要与的数时,更新后这段区间的最小值位置还是更新前的位置。由于一次操作至少将数的一个二进制改变,所以最多改变 (log {INT_{MAX}}) 次,时间复杂度(O(n imes log {INT_{MAX}} imes log {n}))
    当存在两个修改操作时同样操作即可。

    代码:

    #include<bits/stdc++.h>
    #define re register
    using namespace std;
    const int N=500010,MX=2147483647;
    int n,m,a[N];
    struct P { int v,Or,And; };P t[N<<2];
    int lz_or[N<<2],lz_and[N<<2];
    
    template <typename T> inline void read(T &x) {
    	x=0;re char c=getchar();while(c<'0'||c>'9')	c=getchar();
    	while(c>='0'&&c<='9')	x=x*10+(c^48),c=getchar();
    }
    inline int Min(const int &x,const int &y) { return x<y?	x:y; }
    P pushup(P ls,P rs) {
    	P tt; tt.Or=ls.Or|rs.Or,tt.And=ls.And&rs.And;
    	tt.v=Min(ls.v,rs.v); return tt;
    }
    void push_or(int u,int w) {
    	lz_or[u]|=w,lz_and[u]|=w,t[u].v|=w,t[u].Or|=w,t[u].And|=w;
    }
    void push_and(int u,int w) {
    	lz_or[u]&=w,lz_and[u]&=w,t[u].v&=w,t[u].Or&=w,t[u].And&=w;
    }
    void pushdown(int u) {
    	if(lz_or[u]) {
    		push_or(u*2,lz_or[u]),push_or(u*2+1,lz_or[u]);
    		lz_or[u]=0;
    	}
    	if(lz_and[u]!=MX) {
    		push_and(u*2,lz_and[u]),push_and(u*2+1,lz_and[u]);
    		lz_and[u]=MX;
    	}
    }
    void build(int u,int l,int r) {
    	lz_or[u]=0,lz_and[u]=MX;
    	if(l>=r) { t[u].Or=t[u].And=t[u].v=a[l];return ; }
    	int mid=(l+r)>>1; build(u*2,l,mid),build(u*2+1,mid+1,r);
    	t[u]=pushup(t[u*2],t[u*2+1]);
    }
    void mdy_and(int u,int l,int r,int L,int R,int w) {
    	if((t[u].Or&w)==t[u].Or)	return ;
    	if(l==L&&r==R&&(t[u].And&w)==(t[u].Or&w))
    		{ push_and(u,w);return ; }
    	int mid=(l+r)>>1; pushdown(u);
    	if(R<=mid)	mdy_and(u*2,l,mid,L,R,w);
    	else if(L>mid)	mdy_and(u*2+1,mid+1,r,L,R,w);
    	else	mdy_and(u*2,l,mid,L,mid,w),mdy_and(u*2+1,mid+1,r,mid+1,R,w);
    	t[u]=pushup(t[u*2],t[u*2+1]);
    }
    void mdy_or(int u,int l,int r,int L,int R,int w) {
    	if((t[u].And|w)==t[u].And)	return ;
    	if(l==L&&r==R&&(t[u].And|w)==(t[u].Or|w))
    		{ push_or(u,w);return ; }
    	int mid=(l+r)>>1; pushdown(u);
    	if(R<=mid)	mdy_or(u*2,l,mid,L,R,w);
    	else if(L>mid)	mdy_or(u*2+1,mid+1,r,L,R,w);
    	else	mdy_or(u*2,l,mid,L,mid,w),mdy_or(u*2+1,mid+1,r,mid+1,R,w);
    	t[u]=pushup(t[u*2],t[u*2+1]);
    }
    int qry(int u,int l,int r,int L,int R) {
    	if(l==L&&r==R)	return t[u].v;
    	int mid=(l+r)>>1; pushdown(u);
    	if(R<=mid)	return qry(u*2,l,mid,L,R);
    	if(L>mid)	return qry(u*2+1,mid+1,r,L,R);
    	return Min(qry(u*2,l,mid,L,mid),qry(u*2+1,mid+1,r,mid+1,R));
    }
    int main() {
    	int opt,l,r,z;
    	read(n),read(m);
    	for(int i=1;i<=n;i++)	read(a[i]);
    	build(1,1,n);
    	for(;m;--m) {
    		read(opt),read(l),read(r);
    		switch(opt) {
    			case 1: read(z),mdy_and(1,1,n,l,r,z);break;
    			case 2: read(z),mdy_or(1,1,n,l,r,z);break;
    			default:	printf("%d
    ",qry(1,1,n,l,r));break;
    		}
    //		printf("<<< ");
    //		for(int i=1;i<=n;i++)	printf("%d ",qry(1,1,n,i,i));
    //		printf("
    ");
    	}
    	return 0;
    }
    
  • 相关阅读:
    给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
    11
    实战 迁移学习 VGG19、ResNet50、InceptionV3 实践 猫狗大战 问题
    tx2系统备份与恢复
    如何在Ubuntu 18.04上安装和卸载TeamViewer
    bzoj 3732 Network (kruskal重构树)
    bzoj2152 聪聪可可 (树形dp)
    牛客 216D 消消乐 (二分图最小点覆盖)
    牛客 197E 01串
    Wannafly挑战赛23
  • 原文地址:https://www.cnblogs.com/daniel14311531/p/10190959.html
Copyright © 2011-2022 走看看