链接:https://www.nowcoder.com/acm/contest/81/E
来源:牛客网
题目描述
给一个1-base数组{a},有N次操作,每次操作会使一个位置无效。一个区间的权值定义为这个区间里选出一些数的异或和的最大值。求在每次操作前,所有不包含无效位置的区间的权值的最大值。
输入描述:
第一行读入一个正整数(1 <= n <= 105)
第二行读入n个正整数,第i个表示a[i](0<= a[i] <= 109)
第三行读入n个正整数,第i个表示x[i]即第i次操作的位置,保证x[i]互不相同。
输出描述:
输出n行答案
示例1
输入
10
169 816 709 896 58 490 97 254 99 796
4 2 3 10 5 6 1 8 9 7
输出
1023
994
994
994
490
490
254
254
99
97
分析:
根据题目能够想到线性基,又因为正向删去不好处理,可以离线反向进行插入。
在每次插入后,答案可能保留原先的最大值,或者插入的位置构成新的最大值。
然后需要讨论的是插入的位置,是否与左右构成新的区间,如果当前插入位置为x,那么需要看x+1上是否存在值,如果有值,需要进行线性基的合并。以该区间最左边的位置作为合并后的线性基。可用并查集来维护这个位置。然后在看x-1位置上是否有值,如果有,用相同的方式进行线性基的合并。
最后输出得到的线性基的最大值。
代码如下:
#include <cstdio> #include <cstring> #include <string> #include <algorithm> #include <iostream> #include <vector> #include <stack> #include <cstring> using namespace std; const int MAXN=1e5+100; typedef long long LL ; int pre[MAXN]; int vis[MAXN]; LL a[MAXN]; int Find(int x) { int h,tmp; h=x; while(x!=pre[x]) x=pre[x]; while(x!=h) { tmp=pre[h]; pre[h]=x; h=tmp; } return x; } void join(int x,int y) { int p=Find(x); int q=Find(y); if(p<q) pre[q]=p; else if(p>q) pre[p]=q; } struct node { LL id; LL x; LL ans; }qes[MAXN]; struct L_B{ long long d[61],p[61]; int cnt; L_B() { cnt=0; } bool insert(long long val) { for (int i=60;i>=0;i--) if (val&(1LL<<i)) { if (!d[i]) { d[i]=val; break; } val^=d[i]; } return val>0; } long long query_max() { long long ret=0; for (int i=60;i>=0;i--) if ((ret^d[i])>ret) ret^=d[i]; return ret; } long long query_min() { for (int i=0;i<=60;i++) if (d[i]) return d[i]; return 0; } void rebuild() { for (int i=60;i>=0;i--) for (int j=i-1;j>=0;j--) if (d[i]&(1LL<<j)) d[i]^=d[j]; for (int i=0;i<=60;i++) if (d[i]) p[cnt++]=d[i]; } long long kthquery(long long k) { long long ret=0; if (k>=(1LL<<cnt)) return -1; for (int i=60;i>=0;i--) if (k&(1LL<<i)) ret^=p[i]; return ret; } }; L_B merge(const L_B &n1,const L_B &n2) { L_B ret=n1; for (int i=60;i>=0;i--) if (n2.d[i]) ret.insert(n2.d[i]); return ret; } LL n; L_B A[MAXN]; int main() { LL ans=0; scanf("%lld",&n); for(int i=1;i<=n;i++) { pre[i]=i; scanf("%lld",&a[i]); } for(int i=1;i<=n;i++) { qes[i].id=i; scanf("%lld",&qes[i].x); } for(int i=n;i>=1;i--) { A[qes[i].x].insert(a[qes[i].x]); vis[qes[i].x]=1; if(vis[qes[i].x+1]) { A[Find(qes[i].x)]=merge(A[Find(qes[i].x)],A[Find(qes[i].x+1)]); join(qes[i].x,qes[i].x+1); } if(vis[qes[i].x-1]) { A[Find(qes[i].x-1)]=merge(A[Find(qes[i].x-1)],A[Find(qes[i].x)]); join(qes[i].x,qes[i].x-1); } ans=max(ans,A[Find(qes[i].x)].query_max()); qes[i].ans=ans; } for(int i=1;i<=n;i++) cout<<qes[i].ans<<endl; return 0; }