HDU - 6610 Nim博弈+帶修莫隊

可以看出來兩人的遊戲是nim博弈 所以如果區間內的數異或和不爲0 那麼Alice 必勝  

簡單分析一下我們肯定要做一個前綴異或  然後再莫隊就行  因爲Bob會對序列進行修改 所以我們需要用帶修莫隊   然後就變成一個板子題目了

帶修莫隊 在塊大小爲 n^(2/3) 理論上覆雜度最優

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1e5+10,M = 1e6+100;
typedef long long ll;
int xsum[N],p[N],sqn,a[N],blk;
ll tx[M],ans[N],ret;
struct node{
	int l,r,t,id;
	bool operator < (const node &a)const{
		if(l/blk!=a.l/blk) return l/blk<a.l/blk;
		if(r/blk!=a.r/blk) return r/blk<a.r/blk;
		return t<a.t;
	} 
}q[N];
void add(int x){ret+=tx[xsum[x]]++;}
void del(int x){ret-=--tx[xsum[x]];}
void upd(int i,int t){
	int flag=(p[t]<=q[i].r&&p[t]>=q[i].l);
	if(flag) del(p[t]);
	xsum[p[t]]^=a[p[t]],swap(a[p[t]],a[p[t]+1]),xsum[p[t]]^=a[p[t]];
	//printf("xsum=%d\n",xsum[p[t]]);
	if(flag) add(p[t]);
}
int main(){
	int n,m;
	while(~scanf("%d%d",&n,&m)){
		memset(tx,0,sizeof(tx));
		ret=0;
		blk=max(10,(int)pow(n,2./3));
		int qcnt=0,kcnt=0;
		for(int i = 1; i <= n; i++){
			scanf("%d",&a[i]);
			xsum[i]=xsum[i-1]^a[i];
		}
		for(int i = 1; i <= m; i++){
			int op,l,r;
			scanf("%d%d",&op,&l);
			if(op==1){
				scanf("%d",&r);
				q[++qcnt]=(node){l-1,r,kcnt,qcnt};
			}
			else p[++kcnt]=l;
		}
		sort(q+1,q+1+qcnt);
		int l=1,r=0,T=0;
		for(int i = 1; i <= qcnt; i++){
			while(l<q[i].l) del(l++);
			while(l>q[i].l) add(--l);
			while(r<q[i].r) add(++r);
			while(r>q[i].r) del(r--);
			while(T<q[i].t) upd(i,++T);
			while(T>q[i].t)	upd(i,T--);
			ans[q[i].id]=1ll*(q[i].r-q[i].l)*(q[i].r-q[i].l+1)/2ll-ret;
		}
		for(int i = 1; i <= qcnt; i++) printf("%lld\n",ans[i]);
	}
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章