「雅礼集训 2018 Day7」A 题解

「雅礼集训 2018 Day7」A 题解

卡常卡了1.5h

思路

先考虑拆位,则修改相当于区间赋值0/1。

考虑线段树,一次区间赋值,修改的相当于区间内所有当前位不等于修改的位的数。

由于每次都会将区间的值赋值为一个数,所以修改时可以直接暴力修改,直到当前结点的区间内当前的位的数相等。

由于每次修改每多往下递归一次,总种类数都会减少,总共往下递归不超过 O(nlog⁡2n)O(n \log^2 n)O(nlog2n) 次。

代码

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,q,a[500010];
struct N{
	int mn,mx,la0,la1,c;
}tr[2000010];
void pushup(int p){
	tr[p].mn=tr[p<<1].mn&tr[p<<1|1].mn;
	tr[p].mx=tr[p<<1].mx|tr[p<<1|1].mx;
	tr[p].c=min(tr[p<<1].c,tr[p<<1|1].c);
} 
void pushdown(int p){
	int l0=tr[p].la0,l1=tr[p].la1;
	tr[p<<1].c=(tr[p<<1].c&l0)|l1;
	tr[p<<1].mn=(tr[p<<1].mn&l0)|l1;
	tr[p<<1].mx=(tr[p<<1].mx&l0)|l1;
	tr[p<<1].la0=(tr[p<<1].la0&l0)|l1;
	tr[p<<1].la1=(tr[p<<1].la1&l0)|l1;
	tr[p<<1|1].c=(tr[p<<1|1].c&l0)|l1;
	tr[p<<1|1].mn=(tr[p<<1|1].mn&l0)|l1;
	tr[p<<1|1].mx=(tr[p<<1|1].mx&l0)|l1;
	tr[p<<1|1].la0=(tr[p<<1|1].la0&l0)|l1;
	tr[p<<1|1].la1=(tr[p<<1|1].la1&l0)|l1;
	tr[p].la0=(1ll<<31)-1;tr[p].la1=0;
}
void bt(int p,int l,int r){
	tr[p].la0=(1ll<<31)-1;tr[p].la1=0;
	if(l==r){
		tr[p].mn=tr[p].mx=tr[p].c=a[l];
		return ;
	}
	int mid=(l+r)>>1;
	bt(p<<1,l,mid);
	bt(p<<1|1,mid+1,r);
	pushup(p);
}
void change(int p,int l,int r,int x,int y,int h,int v){
	if(((tr[p].mn>>h)&1)==((tr[p].mx>>h)&1)&&((tr[p].mn>>h)&1)==v)return ;
	if(l>=x&&r<=y&&((tr[p].mn>>h)&1)==((tr[p].mx>>h)&1)){
		if((v^((tr[p].mn>>h)&1))){
			tr[p].c^=1<<h;
			tr[p].mn^=1<<h;
			tr[p].mx^=1<<h;
		}
		tr[p].la0^=(v<<h)^(tr[p].la0&(1<<h));
		tr[p].la1^=(v<<h)^(tr[p].la1&(1<<h));
		return ;
	}
	pushdown(p);
	int mid=(l+r)>>1;
	if(x<=mid)change(p<<1,l,mid,x,y,h,v);
	if(y>mid)change(p<<1|1,mid+1,r,x,y,h,v);
	pushup(p);
}
int find(int p,int l,int r,int x,int y){
	if(l>=x&&r<=y)return tr[p].c;
	pushdown(p);
	int mid=(l+r)>>1;
	if(y<=mid)return find(p<<1,l,mid,x,y);
	if(x>mid)return find(p<<1|1,mid+1,r,x,y);
	return min(find(p<<1,l,mid,x,y),find(p<<1|1,mid+1,r,x,y));
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin>>n>>q;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	bt(1,1,n);
	int op,l,r,v;
	for(int _=1;_<=q;_++){
		cin>>op;
		if(op==1){
			cin>>l>>r>>v;
			for(int i=0;i<=30;i++)if(!((v>>i)&1))change(1,1,n,l,r,i,0);
		}
		else if(op==2){
			cin>>l>>r>>v;
			for(int i=0;i<=30;i++)if((v>>i)&1)change(1,1,n,l,r,i,1);
			
		}
		else{
			cin>>l>>r;
			cout<<find(1,1,n,l,r)<<'\n'; 
		}
	}
	return 0;
}
相关推荐
y1su1 小时前
Leetcode 字符串模板
java·数据结构·算法·leetcode·职场和发展·动态规划
residual_fan2 小时前
船用柴油机动态机动工况故障诊断:控制感知仿射网络(CAAN)的技术实现
人工智能·算法·数据挖掘·数据分析
syagain_zsx2 小时前
BRpc 二次封装:Channel 管理、服务管理与回调工厂
c++·学习·程序人生·rpc·谷歌
其实防守也摸鱼2 小时前
Cylab在线靶场——CTF中的通用技能
linux·数据库·学习·算法·靶场·ctf·学习网络安全
蓝悦无人机3 小时前
《Planning algorithms》读书笔记——第8章 反馈运动规划
算法·读书笔记·反馈运动规划
RaaS1003 小时前
Agent Skills 进了 Linux Foundation:2.8 亿次安装,但装 skill 还没有安全规范
人工智能·算法·架构
CV爱数码3 小时前
CT 重建从零开始(五):ASTRA Toolbox 上手——几何、投影器与算法
图像处理·算法·计算机视觉·ct
TunerT_TQ3 小时前
超立方体Ramsey(openai/math 家族171)H11攻坚日志|D60–D69:Star分组重数、二幂坐标群、奇偶入射语义与Site‑Level候选计数形式化闭环
算法
fpcc3 小时前
计算机原理—如何高效的操作文件
c++·计算机原理
Rabitebla4 小时前
【系统性学习笔记】Linux 权限篇(二):文件属性、权限修改与目录权限的底层逻辑
linux·c++·笔记·学习·算法