题目大意:
题目链接:https://jzoj.net/senior/#main/show/3339
一个序列,每次给定,在中选择一个点,先手第一次必须选择在第堆石子内取。求的博弈先手是否有必胜策略,若有择输出第一手先手取的石子个数。
询问之间互相关联。
思路:
对于每一组询问我们枚举区间中的,然后如果先手必胜,则说明先手在中选择若干石子使得。
设。那么则要找到合适的使得。
我们知道,有且仅有形如的情况下才可以等于0。所以我们所求即为。
由于询问直接互相关联,我们不可以用前缀异或和。只需从倒序循环到,每次询问时暴力求异或和。注意只有下标时才可以更新答案。
时间复杂度。显然不可以过卡一卡就过去了。
正解是分块+可持久化。
代码:
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#include <cstdio>
#include <string>
#include <algorithm>
#define reg register
using namespace std;
const int N=100010,Inf=2e9;
int n,T,ans,l,r,R,x,a[N];
int read()
{
int d=0;
char ch=getchar();
while (!isdigit(ch)) ch=getchar();
while (isdigit(ch))
d=(d<<3)+(d<<1)+ch-48,ch=getchar();
return d;
}
void write(int x)
{
if (x>9) write(x/10);
putchar(x%10+48);
}
int main()
{
n=read();
for (reg int i=1;i<=n;i++)
a[i]=read();
T=read();
while (T--)
{
R=read(); l=read(); r=read();
ans=Inf; x=0;
if (!a[R]) puts("-1");
else if (R==r) write(a[r]),putchar(10),a[r]=0;
else
{
for (reg int i=R-1;i>=l;i--)
{
x^=a[i];
if (i<=r&&x<ans) ans=x;
}
if (a[R]-ans>0) write(a[R]-ans),putchar(10),a[R]=ans;
else puts("-1");
}
}
return 0;
}