#树状数组#洛谷 6688 可重集

题目


分析

也就是排序之后的差分数组相同,考虑用树状数组维护区间和,
但是这样很容易被Hack,考虑维护质数的\(a_i\)次幂的和,
判断本质相同直接用区间和相减与区间长度相除求出相差的次数,
直接判断整体乘上这个质数次方是否相等即可


代码

#include <cstdio>
#include <cctype>
#include <cstring>
#define rr register
using namespace std;
const int N=1000011;
typedef unsigned long long ull;
const ull base=331,mod=998244353;
ull H[N],a[N],b[N],C[N],c[N]; int n,Q;
inline ull iut(){
	rr ull ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans; 
}
inline ull mo(ull x,ull y){return x+y>=mod?x+y-mod:x+y;}
inline void Update(int x,ull y){for (;x<=n;x+=-x&x) C[x]=mo(C[x],y);}
inline ull Query(int l,int r){
	rr ull ans=0; --l;
	for (;r>l;r-=-r&r) ans=mo(ans,C[r]);
	for (;l>r;l-=-l&l) ans=mo(ans,mod-C[l]);
	return ans;
}
inline void update(int x,ull y){for (;x<=n;x+=-x&x) c[x]+=y;}
inline ull query(int l,int r){
	rr ull ans=0; --l;
	for (;r>l;r-=-r&r) ans+=c[r];
	for (;l>r;l-=-l&l) ans-=c[l];
	return ans;
}
signed main(){
	n=iut(),Q=iut(),H[0]=1;
	for (rr int i=1;i<N;++i) H[i]=H[i-1]*base%mod;
	for (rr int i=1;i<=n;++i)
	    a[i]=iut(),b[i]=H[a[i]];
	for (rr int i=1;i<=n;++i) c[i]=c[i-1]+a[i];
	for (rr int i=n;i;--i) c[i]-=c[i&(i-1)];
	for (rr int i=1;i<=n;++i) C[i]=mo(C[i-1],b[i]);
	for (rr int i=n;i;--i) C[i]=mo(C[i],mod-C[i&(i-1)]);
	for (rr int i=1;i<=Q;++i){
		rr int z=iut();
		if (!z){
			rr int x=iut(); rr ull y=iut();
			Update(x,mo(H[y],mod-b[x])),b[x]=H[y];
			update(x,y-a[x]),a[x]=y;
		}else{
			rr int lx=iut(),ly=iut(),rx=iut(),ry=iut();
			rr ull ans1=query(lx,ly),ans2=query(rx,ry);
			rr ull Ans1=Query(lx,ly),Ans2=Query(rx,ry);
			if (ans1>ans2){
			    ans1^=ans2,ans2^=ans1,ans1^=ans2,
			    Ans1^=Ans2,Ans2^=Ans1,Ans1^=Ans2;
		    }
		    Ans1=Ans1*H[(ans2-ans1)/(ly-lx+1)]%mod;
			puts(Ans1==Ans2?"YES":"NO");
		}
	}
	return 0;
} 
posted @ 2021-03-10 17:07  lemondinosaur  阅读(60)  评论(0编辑  收藏  举报