【洛谷P6688】可重集

题目

题目链接:https://www.luogu.com.cn/problem/P6688
给出一个长度为 \(n\) 的非负整数序列 \(a_1,a_2,a_3,\ldots, a_n\),给出 \(q\) 次操作,每次先给出一个参数 \(op\)

  • \(op=0\),接下来给出 \(2\) 个参数 \(x,y\),把 \(a_x\) 修改为 \(y\)

  • \(op=1\),接下来给出 \(4\) 个参数 \(l_1,r_1,l_2,r_2\)(保证 \(r_1-l_1=r_2-l_2\)),你需要判断区间 \([l_1,r_1]\) 与区间 \([l_2,r_2]\) 是否本质相同,如果本质相同输出 YES,否则输出 NO

本质相同的定义:令区间长度为 \(\text{len}\) ,序列 \(p_{1}\dots p_{\text{len}}\)\(a_{l_1}\dots a_{r_1}\) 升序排序后的结果,序列 \(q_{1}\dots q_\text{len}\)\(a_{l_2}\dots a_{r_2}\) 升序排序后的结果,存在一个整数 \(k\) 使得满足 \(\forall i,p_i+k=q_i\)

思路

显然这个 \(k\) 只有可能是 \(\frac{\sum^{r_2}_{i=l_2}a[i]-\sum^{r_1}_{i=l_1}a[i]}{r_1-l_1+1}\)
考虑给每一个数字一个特征值 \(f(x)\),这样我们就只需要判断 \(\sum^{r_1}_{i=l_1}f(a[i]+k)\) 是否等于 \(\sum^{r_2}_{i=l_2}f(a[i])\) 即可。
发现这个特征值需要通过若干个已知的数的特征值,得到这中间所有数加上一个整数后的特征值。
所以我们取 \(f(x)=b^x\),其中 \(b\) 最好是质数。这样的话,如果需要求全部加上 \(k\) 的特征值,就只需要再乘 \(b^k\) 即可。
注意这道题卡自然溢出。
时间复杂度 \(O(m\log n)\)

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N=1000010;
const ll base1=5801519,prm1=35807437,base2=13331,prm2=999999491;
int n,m,a[N];

struct BIT
{
	ll c[N];
	
	void add(int x,ll v)
	{
		for (int i=x;i<=n;i+=i&-i)
			c[i]+=v;
	}
	
	ll query(int x)
	{
		ll ans=0;
		for (int i=x;i;i-=i&-i)
			ans+=c[i];
		return ans;
	}
}bit1,bit2,bit3;

ll fpow(ll x,ll k,ll p)
{
	ll ans=1;
	for (;k;k>>=1,x=x*x%p)
		if (k&1) ans=ans*x%p;
	return ans;
}

int main()
{
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		bit1.add(i,a[i]);
		bit2.add(i,fpow(base1,a[i],prm1));
		bit3.add(i,fpow(base2,a[i],prm2));
	}
	while (m--)
	{
		int opt,l1,l2,r1,r2;
		scanf("%d",&opt);
		if (!opt)
		{
			scanf("%d%d",&l1,&l2);
			bit1.add(l1,l2-a[l1]);
			bit2.add(l1,((fpow(base1,l2,prm1)-fpow(base1,a[l1],prm1))%prm1+prm1)%prm1);
			bit3.add(l1,((fpow(base2,l2,prm2)-fpow(base2,a[l1],prm2))%prm2+prm2)%prm2);
			a[l1]=l2;
		}
		else
		{
			scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
			ll k=((bit1.query(r2)-bit1.query(l2-1))-(bit1.query(r1)-bit1.query(l1-1)))/(r1-l1+1);
			if (k<0) k=-k,swap(l1,l2),swap(r1,r2);
			ll s1=(bit2.query(r1)-bit2.query(l1-1))%prm1*fpow(base1,k,prm1)%prm1;
			ll s2=(bit2.query(r2)-bit2.query(l2-1))%prm1;
			ll s3=(bit3.query(r1)-bit3.query(l1-1))%prm2*fpow(base2,k,prm2)%prm2;
			ll s4=(bit3.query(r2)-bit3.query(l2-1))%prm2;
			if ((s1+prm1)%prm1==(s2+prm1)%prm1 && (s3+prm2)%prm2==(s4+prm2)%prm2) printf("YES\n");
				else printf("NO\n");
		}
	}
	return 0;
}
posted @ 2020-12-18 18:41  stoorz  阅读(342)  评论(0编辑  收藏  举报