CF1746F Kazaee 题解
题目描述
给定一个长为 \(n\) 的数组 \(a\) , \(q\) 次操作:
1 i x:将 \(a_i\) 修改为 \(x\) 。2 l r k:询问区间 \([l,r]\) 内是否每个数字的出现次数均为 \(k\) 的倍数。
数据范围
- \(1\le n,q\le 3\cdot 10^5,1\le a_i,x\le 10^9\) 。
时间限制 \(\texttt{3s}\) ,空间限制 \(\texttt{256MB}\) 。
分析
随机化,给每个数字赋随机权值 \(key\) ,统计 \(M=\sum_{i=l}^rkey_{a_i}\) 。
如果所有数字出现次数均为 \(k\) 的倍数,显然有 \(k\mid M\) 。
否则可以认为 \(k\mid M\) 的概率为 \(\frac 1k\) ,随机 \(30\) 次后错误概率 \((\frac 1k)^{30}\lt 10^{-9}\) 。
将出现过的数字离散化,树状数组维护 \(M\) 。
时间复杂度 \(\mathcal O(30(n+q)\log n)\) 。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=6e5+5;
int m,n,q;
int a[maxn],c[maxn];
int k[maxn],l[maxn],r[maxn],op[maxn];
mt19937 rnd(time(0));
struct node
{
int w[maxn];
ll c[maxn];
inline void add(int x,int v)
{
while(x<=n) c[x]+=v,x+=x&(-x);
}
inline ll sum(int x)
{
ll res=0;
while(x) res+=c[x],x-=x&(-x);
return res;
}
inline ll query(int l,int r)
{
return sum(r)-sum(l-1);
}
inline void modify(int p,int v)
{
add(p,-w[a[p]]),add(p,w[v]);
}
inline void init()
{
for(int i=1;i<=m;i++) w[i]=rnd()&((1<<30)-1);
for(int i=1;i<=n;i++) add(i,w[a[i]]);
}
}t[30];
int main()
{
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++) scanf("%d",&a[i]),c[++m]=a[i];
for(int i=1;i<=q;i++)
{
scanf("%d",&op[i]);
if(op[i]==1) scanf("%d%d",&l[i],&k[i]),c[++m]=k[i];
else scanf("%d%d%d",&l[i],&r[i],&k[i]);
}
sort(c+1,c+m+1);
m=unique(c+1,c+m+1)-c-1;
for(int i=1;i<=n;i++) a[i]=lower_bound(c+1,c+m+1,a[i])-c;
for(int j=0;j<30;j++) t[j].init();
for(int i=1;i<=q;i++)
{
if(op[i]==1)
{
int pos=l[i],val=lower_bound(c+1,c+m+1,k[i])-c;
for(int j=0;j<30;j++) t[j].modify(pos,val);
a[pos]=val;
}
else
{
int flg=1;
for(int j=0;j<30;j++) flg&=t[j].query(l[i],r[i])%k[i]==0;
printf(flg?"YES\n":"NO\n");
}
}
return 0;
}
本文来自博客园,作者:peiwenjun,转载请注明原文链接:https://www.cnblogs.com/peiwenjun/p/17318360.html
浙公网安备 33010602011771号