T1:
题解:
分类讨论一下,如果前面的数>后面的数,那么对应2进制位前面的为0,后面的为1的最高位不能异或;如果前面的数< 后面的数,那么前面为1,后面为0的最高位必须异或;等于的话随便异或
那么我们有两个条件,一个是允许(ok),另一个是必须(must),如果must的不ok就是-1,如果不是-1就把所有must的二进制加起来
考场上写了O(qlog2n)O(qlog2n)的线段树80pts,每个叶子节点是相邻两个节点的must和ok,如果用bitset维护的话,update的时候就可以直接ok&,must|。那么每次修改相关的只有这个点和左边的点&&这个点和右边的点,复杂度O(log2n)O(log2n)
考虑优化。可以发现每次修改x,都只跟x-1和x+1有关,那么每次修改都记录不被允许&&必须的个数,不被允许的那一位不为0意为不允许,必须的那一位不为0意为必须,单次修改O(logn),可以通过100pts
代码:
80pts(数据结构学傻的人
#include <cstring>
#include <cstdio>
#include <bitset>
#define LL long long
using namespace std;
const int sz=35;
const int N=2000005;
bitset <sz> ok[N*4],must[N*4];
int num[N+5][sz+5];LL a[N+5];
void updata(int now)
{
must[now]=must[now<<1]|must[now<<1|1];
ok[now]=ok[now<<1]&ok[now<<1|1];
}
void build(int now,int l,int r)
{
if (l==r)
{
for (int i=0;i<=sz;i++) ok[now][i]=1,must[now][i]=0;
if (a[l]<=a[l+1])
{
for (int j=sz;j>=0;j--)
if (num[l][j]==0 && num[l+1][j]==1) {ok[now][j]=0; break;}
}else
{
for (int j=sz;j>=0;j--)
if (num[l][j]==1 && num[l+1][j]==0) {must[now][j]=1; break;}
}
return;
}
int mid=(l+r)>>1;
build(now<<1,l,mid);
build(now<<1|1,mid+1,r);
updata(now);
}
void change(int now,int l,int r,int x)
{
if (l==r)
{
for (int i=0;i<=sz;i++) ok[now][i]=1,must[now][i]=0;
if (a[l]<=a[l+1])
{
for (int j=sz;j>=0;j--)
if (num[l][j]==0 && num[l+1][j]==1) {ok[now][j]=0; break;}
}else
{
for (int j=sz;j>=0;j--)
if (num[l][j]==1 && num[l+1][j]==0) {must[now][j]=1; break;}
}
return;
}
int mid=(l+r)>>1;
if (x<=mid) change(now<<1,l,mid,x);
else change(now<<1|1,mid+1,r,x);
updata(now);
}
LL work()
{
LL ans=0;
for (int i=sz;i>=0;i--)
if (must[1][i] && !ok[1][i]) return -1;
for (int i=sz;i>=0;i--)
if (must[1][i]) ans|=(1<<i);
return ans;
}
int main()
{
freopen("repair.in","r",stdin);
freopen("repair.out","w",stdout);
int n;scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
for (int j=sz;j>=0;j--)
if (a[i]>>j&1) num[i][j]=1;else num[i][j]=0;
}
build(1,1,n-1);
if (n==1) printf("0");
else printf("%lld\n",work());
int q;scanf("%d",&q);
while (q--)
{
int x;LL v;
scanf("%d%lld",&x,&v);
a[x]=v;
for (int j=sz;j>=0;j--)
if (a[x]>>j&1) num[x][j]=1;else num[x][j]=0;
change(1,1,n-1,x); change(1,1,n-1,x-1);
if (n==1) printf("0");
else printf("%lld\n",work());
}
}
100pts
#include <cstdio>
#define LL long long
using namespace std;
const int sz=35;
const int N=2000005;
int num[N+5][sz+5],ok[N],must[N];LL a[N];
int find(LL x,LL y)
{
LL xin=x^y;
for (int i=sz;i>=0;i--)
if (xin>>i&1) return i;
}
LL work()
{
LL ans=0;
for (int i=sz;i>=0;i--)
if (must[i] && ok[i]) return -1;
for (int i=sz;i>=0;i--)
if (must[i]) ans|=(1<<i);
return ans;
}
int main()
{
freopen("repair.in","r",stdin);
freopen("repair.out","w",stdout);
int n;scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%lld",&a[i]);
for (int i=2;i<=n;i++)
if (a[i-1]<a[i]) ok[find(a[i-1],a[i])]++;
else if (a[i-1]>a[i]) must[find(a[i-1],a[i])]++;
printf("%lld\n",work());
int q;scanf("%d",&q);
while (q--)
{
int i;LL v;
scanf("%d%lld",&i,&v);
if (i!=1)
{
if (a[i-1]<a[i]) ok[find(a[i-1],a[i])]--;
else if (a[i-1]>a[i]) must[find(a[i-1],a[i])]--;
}
if (i!=n)
{
if (a[i]<a[i+1]) ok[find(a[i],a[i+1])]--;
else if (a[i]>a[i+1]) must[find(a[i],a[i+1])]--;
}
a[i]=v;
if (i!=1)
{
if (a[i-1]<a[i]) ok[find(a[i-1],a[i])]++;
else if (a[i-1]>a[i]) must[find(a[i-1],a[i])]++;
}
if (i!=n)
{
if (a[i]<a[i+1]) ok[find(a[i],a[i+1])]++;
else if (a[i]>a[i+1]) must[find(a[i],a[i+1])]++;
}
printf("%lld\n",work());
}
}