题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6610
题目大意:
Alice和Bob在玩石子游戏,Alice选择一个区间【L,R】,确定玩游戏的区间,Bob再选择一个【l,r】,
因为每次Alice可以先走,所以为了让游戏更加公平,Bob可以在每次游戏开始的时候先选择一个点pos,将pos与pos+1的石头堆
的石头数量交换。现在给你很多种操作和询问,
op==1,就会给你一个[L,R]的区间,你要回答在这个区间内有多少个l,r,Bob选择了之后Alice可以赢
op==2,表示Bob将pos和pos+1的石头进行了对换。
思路:
考虑没有任何骚操作的情况,Alice在选择了一个区间后,有多少个子区间l,r,Alice是必败的?
很显然这是一个简单的NIm游戏,只要这个子区间的异或和为0,那么Bob选择这个子区间后Alice就必败
那么什么情况下区间的异或和为0呢?只要区间起点和终点的前缀异或和相同,那么这个区间异或和就为0
所以问题就转化为了:给你一个区间,询问这个区间中相同的数的个数有多少对?
是不是莫队模板题?没错,不过现在多了个修改操作,那就带修改莫队模板嘛,冲就完了。
离散化超时了,开了个1e6数组
#include <bits/stdc++.h>
using namespace std;
/*
单点修改莫队板子
*/
typedef long long ll;
const int maxn=1e5+10;
const int maxm=1e6+10;
//const int maxm=1e6+10;
int a[maxn];
//询问
ll sum[maxn],p[maxn],block;//分块,带修改的分块最好为2/3
struct Query{
int l,r;
int id;
int t;//时间轴,因为有修改操作
Query(int _l,int _r,int _id,int _t):l(_l),r(_r),id(_id),t(_t){}
Query(){}
}q[maxn];
int cmp(Query x,Query y){
if(x.l/block!=y.l/block) return x.l/block<y.l/block;
if(x.r/block!=y.r/block) return x.r/block<y.r/block;
return x.t<y.t;
}
ll ANS[maxn];//答案
ll ans;
ll bar[maxm];//区间不同的数
/*
离散化超时了。。。
vector<ll>v;//离散化
int getid(int cur){
return lower_bound(v.begin(),v.end(),cur)-v.begin()+1;
}
*/
//莫队加减模板
void add(int pos){
ans+=bar[sum[pos]];
bar[sum[pos]]++;
}
void del(int pos){
ans-=--bar[sum[pos]];
}
//待修改的莫队
void modify_t(int i,int t){
int flag=q[i].l<=p[t]&&p[t]<=q[i].r;//在这个询问区间内
if(flag){
del(p[t]);
}
sum[p[t]]^=a[p[t]],swap(a[p[t]],a[p[t]+1]),sum[p[t]]^=a[p[t]];//相当于先减去,再交换,再加上来
if(flag){
add(p[t]);
}
}
signed main(){
int n,m;
while(scanf("%d%d",&n,&m)!=EOF){
//v.clear();
for(int i=0;i<maxn;i++)bar[i]=0;
block=max(1ll*10,(ll)pow(n,2.0/3));
sum[0]=0;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
sum[i]=sum[i-1]^a[i];
//v.push_back(sum[i]);
}
int qcnt=0,kcnt=0;
//sort(v.begin(),v.end());
// v.erase(unique(v.begin(),v.end()),v.end());
while(m--){
int op;
scanf("%d",&op);
if(op==1){
int l,r;
scanf("%d%d",&l,&r);
q[++qcnt]=Query(l-1,r,qcnt,kcnt);//kcnt用来表示时间,以修改操作改变时间
}
else{
int t;
scanf("%d",&t);
p[++kcnt]=t;
}
}
sort(q+1,q+qcnt+1,cmp);
int dexl=1,dexr=0,tt=0;ans=0;
for(int i=1;i<=qcnt;++i){
while(dexr<q[i].r) add(++dexr);
while(dexl>q[i].l) add(--dexl);
while(dexr>q[i].r) del(dexr--);
while(dexl<q[i].l) del(dexl++);
while(tt<q[i].t) modify_t(i,++tt);
while(tt>q[i].t) modify_t(i,tt--);
ANS[q[i].id]=(ll)(q[i].r-q[i].l)*(q[i].r-q[i].l+1)/2-ans;
}
for(int i=1;i<=qcnt;i++){
printf("%lld\n",ANS[i]);
}
}
return 0;
}