【洛谷P3792】由乃与大母神原型和偶像崇拜(随机化)(树状数组)

传送门


解析:

数组开小TLE了若干次 (在线丢人)

其实想法还是很简单的,考虑离散化,为了保证离散化前不连续的值离散化后也不连续,我们将每个每个值+1放进数组中。

给每个值赋上一个随机值,然后树状数组维护前缀和,前缀异或和。

每个修改直接在树状数组里面修改。

询问先查询区间和,求出值域连续情况下的左右端点,然后看一下区间异或和和原值域上异或和是否相等。


代码(不要问我为什么unsigned long long 用 u32 来 typedef):

#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc get_char
#define cs const

namespace IO{
	inline char get_char(){
		static cs int Rlen=1<<20|1;
		static char buf[Rlen],*p1,*p2;
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
	}
	
	inline int getint(){
		re char c;
		while(!isdigit(c=gc()));re int num=c^48;
		while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
		return num;
	}
}
using namespace IO;

using std::cout;
using std::cerr;
typedef unsigned ll u32;

cs int N=5e5+5;
int n,m;
int a[N],b[N<<2],len;

struct Opt{
	int typ,x,y;
}opt[N];

std::mt19937 R(19491001);
u32 p[N<<2],pre[N<<2],sum[N],xsum[N];

inline void adds(int pos,int val){
	for(;pos<=n;pos+=pos&-pos)sum[pos]+=val;
}

inline u32 querys(int pos){
	u32 res=0;
	for(;pos>0;pos^=pos&-pos)res+=sum[pos];
	return res;
}

inline void addx(int pos,u32 val){
	for(;pos<=n;pos+=pos&-pos)xsum[pos]^=val;
}

inline u32 queryx(int pos){
	u32 res=0;
	for(;pos>0;pos^=pos&-pos)res^=xsum[pos];
	return res;
}

signed main(){
	n=getint(),m=getint();
	for(int re i=1;i<=n;++i){
		a[i]=getint();
		b[++len]=a[i];
		b[++len]=a[i]+1;
	}
	for(int re i=1;i<=m;++i){
		opt[i].typ=getint();
		opt[i].x=getint();
		opt[i].y=getint();
		if(opt[i].typ==1){
			b[++len]=opt[i].y;
			b[++len]=opt[i].y+1;
		}
	}
	std::sort(b+1,b+len+1);
	len=std::unique(b+1,b+len+1)-b-1;
	for(int re i=1;i<=n;++i)a[i]=std::lower_bound(b+1,b+len+1,a[i])-b;
	for(int re i=1;i<=m;++i)if(opt[i].typ==1)opt[i].y=std::lower_bound(b+1,b+len+1,opt[i].y)-b;
	for(int re i=1;i<=len;++i){
		p[i]=((unsigned ll)R()<<32)^R();
		pre[i]=pre[i-1]^p[i];
	}
	for(int re i=1;i<=n;++i){
		adds(i,a[i]);
		addx(i,p[a[i]]);
	}
	for(int re i=1;i<=m;++i)switch(opt[i].typ){
		case 1:{
			adds(opt[i].x,opt[i].y-a[opt[i].x]);
			addx(opt[i].x,p[opt[i].y]^p[a[opt[i].x]]);
			a[opt[i].x]=opt[i].y;
			break;
		}
		case 2:{
			int mid=(querys(opt[i].y)-querys(opt[i].x-1))/(opt[i].y-opt[i].x+1);
			int l=mid-(opt[i].y-opt[i].x)/2;
			int r=l+opt[i].y-opt[i].x;
			if(l<=0||r>len)puts("yuanxing");
			else if((queryx(opt[i].y)^queryx(opt[i].x-1))==(pre[r]^pre[l-1]))puts("damushen");
			else puts("yuanxing");
			break;
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值