HDU - 6610 Game(带修莫队)

题目链接:点击查看

题目大意:给出一个长度为 n 的序列 a,sum 为数列 a 的前缀异或和,再给出 m 次操作,每次操作分为两种类型:

  1. 1 l r:询问 sum 在区间 [ l , r ] 内有多少对不重复的数
  2. 2 pos:交换 a[ pos ] 和 a[ pos + 1 ] 位置的数

题目分析:参考博客:https://blog.csdn.net/qq_42576687/article/details/98211361

带修莫队模板题,存个板子,对于这个题目而言,转换后的题意如上,因为修改操作对于前缀异或和的影响只有 pos 位置受到影响,其他位置不受影响,所以可以视为单点修改,询问有多少对不重复的数,正难则反,可以用总数减去区间内有多少对重复的数即可

分块大小为 \small n^{\frac{2}{3}} ,时间复杂度为 \small n^{\frac{5}{3}}

相对于普通莫队而言,只是在结构体中多了一个变量 t ,代表当前询问之前有多少次修改,在处理时 while 循环也多了两重,需要放在端点修改的 while 之后

修改的话需要分类讨论一下,如果当前修改的点位于当前询问的区间内,则需要对区间的贡献同样做出修改,否则的话不用处理

代码:
 

#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
using namespace std;

typedef long long LL;

typedef unsigned long long ull;

const int inf=0x3f3f3f3f;

const int N=1e5+100;

int size,n,m,a[N],sum[N],p[N],qcnt,pcnt;

LL cnt[N*10],ans[N];

struct query
{
	int l,r,id,t;
	bool operator<(const query& a)const
	{
		if(l/size!=a.l/size)
			return l<a.l;
		else if(r/size!=a.r/size)
			return r<a.r;
		else
			return t<a.t;
	}
}q[N];

LL add(int pos)
{
	return cnt[sum[pos]]++;
}

LL del(int pos)
{
	return --cnt[sum[pos]];
}

LL modify(int id,int pos)
{
	LL ans=0;
	bool flag=q[id].l<=p[pos]&&p[pos]<=q[id].r;
	if(flag)
		ans-=del(p[pos]);
	sum[p[pos]]^=a[p[pos]];
	swap(a[p[pos]],a[p[pos]+1]);
	sum[p[pos]]^=a[p[pos]];
	if(flag)
		ans+=add(p[pos]); 
	return ans;
}

void solve()
{
	sort(q+1,q+1+qcnt);
	int l=1,r=0,t=0;
	LL sum=0;
	for(int i=1;i<=qcnt;i++)
	{
		int ql=q[i].l,qr=q[i].r,qt=q[i].t;
		while(r<qr)
			sum+=add(++r);
		while(l>ql)
			sum+=add(--l);
		while(r>qr)
			sum-=del(r--);
		while(l<ql)
			sum-=del(l++);
		while(t<qt)
			sum+=modify(i,++t);
		while(t>qt)
			sum+=modify(i,t--);
		ans[q[i].id]=1LL*(qr-ql+1)*(qr-ql)/2-sum;
	}
}

int main()
{
#ifndef ONLINE_JUDGE
//  freopen("data.in.txt","r",stdin);
//  freopen("data.out.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		memset(cnt,0,sizeof(cnt));
		size=(int)pow(n,2.0/3.0);
		for(int i=1;i<=n;i++)
		{
			scanf("%d",a+i);
			sum[i]=sum[i-1]^a[i];
		}
		qcnt=0,pcnt=0;
		while(m--)
		{
			int op;
			scanf("%d",&op);
			if(op==1)
			{
				int l,r;
				scanf("%d%d",&l,&r);
				qcnt++;
				q[qcnt].l=l-1,q[qcnt].r=r,q[qcnt].t=pcnt,q[qcnt].id=qcnt;
			}
			else
			{
				int pos;
				scanf("%d",&pos);
				p[++pcnt]=pos;
			}
		}
		solve();
		for(int i=1;i<=qcnt;i++)
			printf("%lld\n",ans[i]);
	}















    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_45458915/article/details/106958683