题目链接:点击查看
题目大意:给出一个长度为 n 的序列 a,sum 为数列 a 的前缀异或和,再给出 m 次操作,每次操作分为两种类型:
- 1 l r:询问 sum 在区间 [ l , r ] 内有多少对不重复的数
- 2 pos:交换 a[ pos ] 和 a[ pos + 1 ] 位置的数
题目分析:参考博客:https://blog.csdn.net/qq_42576687/article/details/98211361
带修莫队模板题,存个板子,对于这个题目而言,转换后的题意如上,因为修改操作对于前缀异或和的影响只有 pos 位置受到影响,其他位置不受影响,所以可以视为单点修改,询问有多少对不重复的数,正难则反,可以用总数减去区间内有多少对重复的数即可
分块大小为 ,时间复杂度为
相对于普通莫队而言,只是在结构体中多了一个变量 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;
}