Problem Description
daxia和suneast玩起来取石子游戏,现有n堆石子放成一排,每堆石子颗数为a1,a2,...,an.
然后开始m轮游戏,每轮游戏之前,suneast先把第i堆的石子改成x颗,然后双方开始在第j堆到第k堆之间进行取石子游戏.
取石子规则如下:
1. daxia先取,然后双方轮流,每次取的数量不得超过该堆的一半;
2. 当轮到某一方,而其不能取到石子的时候,则判其为负.
Input
测试包含多组数据.
每组数据第一行为2个整数n(0<n<=100000),m(0<m<=100000).
接下来包含一行,共n个整数ai(0<ai<=1000000000).
接下来包含m行,每行4个整数i,x,j,k(1<=i,j,k<=n,0<x<=1000000000).
Output
每组数据输出m行,如果为daxia胜输出"daxia",suneast胜则输出"suneast".
Sample Input
Sample Output
Hint
第一轮改后(2 1 1),区间[1,3],daxia取完第一堆一颗获胜
第二轮改后(3 1 1),区间[1,2],daxia和suneast各在第一堆取一颗后,suneast获胜
第三轮改后(3 2 1),区间[3,3],daxia上来就没得取,suneast获胜
以前做过类似的题,不过那是一个堆,也是只能取不超过一半石子,那题是打表找规律,这题也是。给你ai,它的sg值=x ,满足a[i]=2^(y)*(2*x+1)
求出x后,[j,k]区间异或就是答案,但还要支持单点修改,那就是单点修改,区间求异或和,所以线段树,树状数组都可以高效解决。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <set>
#include <cmath>
#include <algorithm>
#include <map>
using namespace std;
const int maxn=2e5+10;
int a[maxn];
int bit[maxn];
int sum(int i){
int ans=0;
while(i>0){
ans^=bit[i];
i-=i&-i;
}
return ans;
}
void add(int i,int x,int xx){
while(i<maxn){
bit[i]=x^xx^bit[i];
i+=i&-i;
}
}
inline int ca(int x){
x++;
if(x==0)return 0;
while( !(x&1) ){
x>>=1;
}
return (x-1)/2;
}
int main()
{
//for(int i=0;i<100;i++)printf("%d\n",ca(i));
int n,m;
while(~scanf("%d%d",&n,&m)){
memset(bit,0,sizeof(bit));
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
a[i]=ca(a[i]);
add(i,a[i],0);
}
int i,x,j,k;
for(int p=1;p<=m;p++){
scanf("%d%d%d%d",&i,&x,&j,&k);
x=ca(x);
add(i,x,a[i]);
a[i]=x;
int t1=min(j,k);int t2=max(k,j);
int ans=sum(t2)^sum(t1-1);
if(ans)printf("daxia\n");
else printf("suneast\n");
}
}
return 0;
}