Luogu3792 由乃与大母神原型和偶像崇拜

Description

link

Solution

引理:现在有两个正整数集合 ({S},{T})({S} e {T},|S|=|T|)

则有:(sumlimits_{xin S} 2^x e sumlimits_{yin T}2^y)

证明:由二进制考虑,就证完了

然后我们维护上这个区间 (2) 的次幂和,和区间 (min)(max)

在判断区间是不是满足的时候直接 (min) (max) 等比数列求个和就好了

这个题我并不知道是不是在次方足够大的时候可以直接取 (x^p) 就可以满足条件了

(但是据说维护平方和就能过去了?)

需要 (hash)

三个模数会挂,(998244353) 一个就能过了

Code

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define reg register
namespace yspm{
	inline int read()
	{
		int res=0,f=1; char k;
		while(!isdigit(k=getchar())) if(k=='-') f=-1;
		while(isdigit(k)) res=res*10+k-'0',k=getchar();
		return res*f;
	}
	const int N=5e5+10;
	int mod=998244353,a[N],n,T;
	inline int ksm(int x,int y,int z)
	{
		int res=1; for(;y;y>>=1,(x*=x)%=z) if(y&1) (res*=x)%=z;
		return res;
	}
	inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
	struct node{
		int l,r,sum,minn,maxx;
		#define l(p) t[p].l
		#define r(p) t[p].r
		#define sum(p) t[p].sum
		#define minn(p) t[p].minn
		#define maxx(p) t[p].maxx
	}t[N<<2];
	inline int min(int x,int y){return x<y?x:y;}
	inline int max(int x,int y){return x>y?x:y;}
	inline void push_up(int p)
	{
		minn(p)=min(minn(p<<1),minn(p<<1|1)); 
		maxx(p)=max(maxx(p<<1),maxx(p<<1|1)); 
		sum(p)=add(sum(p<<1),sum(p<<1|1));
		return ;
	}
	inline void build(int p,int l,int r)
	{
		l(p)=l; r(p)=r; 
		if(l==r)
		{
			minn(p)=maxx(p)=a[l];
			sum(p)=ksm(2,a[l],mod);
			return ;
		}
		int mid=(l+r)>>1; 
		build(p<<1,l,mid); build(p<<1|1,mid+1,r);
		return push_up(p);
	}
	inline void update(int p,int x,int d)
	{
		if(l(p)==x&&r(p)==x)
		{
			minn(p)=maxx(p)=d;
			sum(p)=ksm(2,d,mod);
			return ;
		} int mid=(l(p)+r(p))>>1;
		if(x<=mid) update(p<<1,x,d);
		else update(p<<1|1,x,d);
		return push_up(p);
	}
	inline node ask(int p,int l,int r)
	{
		if(l<=l(p)&&r(p)<=r) return t[p];
		int mid=(l(p)+r(p))>>1;
		if(l>mid) return ask(p<<1|1,l,r);
		if(r<=mid) return ask(p<<1,l,r);
		node ans; node t1=ask(p<<1,l,r),t2=ask(p<<1|1,l,r);
		ans.maxx=max(t1.maxx,t2.maxx); 
		ans.minn=min(t1.minn,t2.minn);
		ans.sum=add(t1.sum,t2.sum);
		return ans;
	}
	signed main()
	{
		n=read(); T=read();
		for(reg int i=1;i<=n;++i) a[i]=read();
		build(1,1,n);
		while(T--)
		{
			int opt=read();
			if(opt==1)
			{
				int pos=read(),val=read();
				update(1,pos,val);	
			}
			else 
			{
				int l=read(),r=read();
				node res=ask(1,l,r); 
				if(res.maxx-res.minn!=r-l){puts("yuanxing"); continue;}
				int tsum=(ksm(2,res.maxx+1,mod)-ksm(2,res.minn,mod)+mod)%mod;
				if(tsum!=res.sum) puts("yuanxing"); 
				else puts("damushen");
			}
		}
		return 0;
	}
}
signed main(){return yspm::main();}

Review

不错的线段树题,把线段树当做工具使用的那种题

原文地址:https://www.cnblogs.com/yspm/p/12807539.html