题目描述
作为一道签到题,自然只能包含最基本的算法。本题的任务很简单,给定一个长度为n的序列a,你要将其排序。
由于出题人很菜,不会排序算法,他决定自己编一个。他想找到一个数x,使得序列中的所有数字都异或上x后序列恰好按从小到大排列。
顺带,这个序列会被进行若干次修改,每次修改后你需要回答当前是否存在一个x满足序列中数字异或上x后按从小到大排列,如果有,请你给出最小的x。
由于出题人很菜,不会排序算法,他决定自己编一个。他想找到一个数x,使得序列中的所有数字都异或上x后序列恰好按从小到大排列。
顺带,这个序列会被进行若干次修改,每次修改后你需要回答当前是否存在一个x满足序列中数字异或上x后按从小到大排列,如果有,请你给出最小的x。
输入
第一行一个正整数n。
第二行n个非负整数,表示序列a。
第三行一个非负整数q,表示修改次数。
接下来q行,每行一个正整数x和一个非负整数y,表示将序列中第x个元素修改为y
第二行n个非负整数,表示序列a。
第三行一个非负整数q,表示修改次数。
接下来q行,每行一个正整数x和一个非负整数y,表示将序列中第x个元素修改为y
输出
输出q+1行,每行一个整数,第一行表示一开始最小的合法x,之后q行依次表示每次修改后最小的合法x,如果不存在则这一行输出−1。
样例输入
3 0 1 4 3 2 7 3 3 1 4
样例输出
0 2 -1 4
提示
对于100%的数据,n,m≤106,所有数字不超过230。
请注意输入输出效率对程序运行时间的影响。
两个数的大小差异在于其二者二进制位相异的最高一位,若在这一位异或1,两数的大小关系能得到反转,在除这位外的任何一位异或0/1,大小关系不会改变

#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,a[1000005];
int cnt[35][5];
void solve(){
int ret=0;
for(int i=30;i>=0;--i){
if(cnt[i][1]&&cnt[i][0]){
printf("-1\n");
return;
}
if(cnt[i][1]){
ret|=(1<<i);
}
}
printf("%d\n",ret);
return;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=2;i<=n;++i){
for(int j=30;j>=0;--j){
if((a[i]^a[i-1])&(1<<j)){
cnt[j][a[i-1]>a[i]]++;
break;
}
}
}
solve();
int q;scanf("%d",&q);
int x,y;
while(q--){
scanf("%d%d",&x,&y);
if(x>1){
for(int i=30;i>=0;--i){
if((a[x]^a[x-1])&(1<<i)){
cnt[i][a[x-1]>a[x]]--;
break;
}
}
for(int i=30;i>=0;--i){
if((y^a[x-1])&(1<<i)){
cnt[i][a[x-1]>y]++;
break;
}
}
}
if(x<n){
for(int i=30;i>=0;--i){
if((a[x]^a[x+1])&(1<<i)){
cnt[i][a[x]>a[x+1]]--;
break;
}
}
for(int i=30;i>=0;--i){
if((y^a[x+1])&(1<<i)){
cnt[i][y>a[x+1]]++;
break;
}
}
}
a[x]=y;
solve();
}
return 0;
}
来源:https://www.cnblogs.com/lllxq/p/10509774.html
