题目链接: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;
}