CF1746F

发现直接维护区间内每个数的出现次数并不好做。不妨把这个条件外推,假设 \([l,r]\) 中每个数的出现次数都是 \(k\) 的倍数,那么 \(\sum_{i=l}^r a_i\) 也是 \(k\) 的倍数,即后者是前者的必要条件,并且当 \(a_i\) 较大时,后者成立时前者成立的概率会越大。

因此我们可以这样判定:如果 \(\sum_{i=l}^r a_i\)\(k\) 的倍数,那么 \([l,r]\) 中每个数的出现次数都是 \(k\) 的倍数。当然,在此之前,我们要对 \(a_i\)(以及修改的值)进行随机替换(只需确保原本相同的数替换后仍相同),从而提高判定正确率。判定需要进行一定的次数,我取了 \(30\) 次。初始时假定都是成立的,一旦有一次判定不成立即为不成立。若干次以后,错误率已经极低了,基本可以忽略。

于是用树状数组维护序列即可。随机时可以使用 mt19937 以增大随机数的分布范围。

#include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#define int long long
#define N 1000001

using namespace std;

mt19937 rnd( time( NULL ) );

struct Q
{
	int op,l,r,k,x,y,flag;
}q[N];

int n,a[N],b[N],c[N],d[N],f[N],t[N],tot,m;

int lowbit( int x )
{
	return x & ( -x );
}

void upd( int x , int y )
{
	for( int i = x ; i <= n ; i += lowbit( i ) )
		t[i] += y;
	return;
}

int que( int x )
{
	int sum = 0;
	for( int i = x ; i >= 1 ; i -= lowbit( i ) )
		sum += t[i];
	return sum;
}

signed main()
{
	ios::sync_with_stdio( false );
	cin.tie( 0 );
	cout.tie( 0 );
	cin >> n >> m;
	for( int i = 1 ; i <= n ; i ++ )
		cin >> a[i],c[++ tot] = a[i];
	for( int i = 1 ; i <= m ; i ++ )
	{
		cin >> q[i].op;
		if( q[i].op == 1 )
			cin >> q[i].x >> q[i].y,c[++ tot] = q[i].y;
		if( q[i].op == 2 )
			cin >> q[i].l >> q[i].r >> q[i].k,q[i].flag = 1;
	}
	sort( c + 1 , c + tot + 1 );
	tot = unique( c + 1 , c + tot + 1 ) - c - 1;
	for( int i = 1 ; i <= n ; i ++ )
		a[i] = lower_bound( c + 1 , c + tot + 1 , a[i] ) - c;
	for( int i = 1 ; i <= m ; i ++ )
		if( q[i].op == 1 )
			q[i].y = lower_bound( c + 1 , c + tot + 1 , q[i].y ) - c;
	int T = 30;
	while( T -- )
	{
		for( int i = 1 ; i <= tot ; i ++ )
			b[i] = rnd() % 1000000007 + 1;
		for( int i = 1 ; i <= n ; i ++ )
			t[i] = 0;
		for( int i = 1 ; i <= n ; i ++ )
			upd( i , b[a[i]] ),f[i] = a[i];
		for( int i = 1 ; i <= m ; i ++ )
		{
			if( q[i].op == 1 ) upd( q[i].x , b[q[i].y] - b[f[q[i].x]] ),f[q[i].x] = q[i].y;
			if( q[i].op == 2 )
			{
				if( ( que( q[i].r ) - que( q[i].l - 1 ) ) % q[i].k )
					q[i].flag = 0;
			}
		}
	}
	for( int i = 1 ; i <= m ; i ++ )
		if( q[i].op == 2 )
		{
			if( q[i].flag ) cout << "YES\n";
			else cout << "NO\n";
		}
	return 0;
}
posted @ 2025-09-08 18:39  FormulaOne  阅读(19)  评论(0)    收藏  举报