牛客网 Wannafly挑战赛14 E.无效位置 (并查集+线性基)

链接: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;
}

猜你喜欢

转载自www.cnblogs.com/a249189046/p/8953782.html