【2019HDU多校】HDU6579 线性基

传送门

题意是说会依次给m次操作,要么在序列后面加一个数,要么问你区间[L, R]里的最大异或和。

做法很有技巧。维护前缀的线性基。f[x][i]代表前x个数第i位的代表的基是哪个数。

但是不是一般的方法直接维护,而是只留下最靠后加入的。所以还需要一个pos[x][i]代表f[x][i]是第几个数。

这样在查询f[r][i]的时候如果第i位的pos是小于l的(pos[r][i] < l),这一位就不合法舍去。

因为在插入的时候是在此位存在的情况下维护尽量靠后的。所以答案一定是最大的。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e5 + 233;
int f[maxn][33], pos[maxn][33];
inline int Read() 
{
    int x=0,f=1; char ch=getchar(); 
    while (ch<'0'||ch>'9') {if (ch=='-') f=-f; ch=getchar();}
    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
char s[30];
inline void writeln(int x)
{
    if (x<0) putchar('-'),x=-x; 
    if (!x) putchar('0'); else 
    {
        int len=0;  
        while (x) s[++len]=x%10+'0',x/=10;
          while (len) putchar(s[len--]);
    } 
    putchar('\n');
}
void add(int x, int v)
{
    for(int i = 30; i >= 0; --i) f[x][i] = f[x - 1][i], pos[x][i] = pos[x - 1][i];
    int t = x;
    for(int i = 30; i >= 0; --i)
    {
        if(v >> i)
        {
            if(!f[x][i]) 
            {
                f[x][i] = v, pos[x][i] = t;
                break;
            }
            else  
            {
                if(pos[x][i] < t)
                    swap(pos[x][i], t), swap(f[x][i], v);
                v ^= f[x][i];
            }
        }
    }
}
int main()
{
    int T; 
    scanf("%d", &T);
    while(T--)
    {
        int n, m;
        scanf("%d%d", &n, &m);
        int k;
        for(int i = 1; i <= n; ++i) k = Read(), add(i, k);
        int ans = 0;
        int l, r; 
        for(int j = 1; j <= m; ++j)
        {
            int op; //scanf("%d", &op);
            op = Read();
            if(op == 0)
            {
                //scanf("%d%d", &l, &r);
                l = Read(), r = Read();
                l ^= ans, r ^= ans;
                l = l % n + 1, r = r % n + 1;
                if(l > r) swap(l, r);
                ans = 0;
                for(int i = 30; i >= 0; --i)
                {
                    if(pos[r][i] >= l && ((ans ^ f[r][i]) > ans)) ans ^= f[r][i];
                }
                printf("%d\n", ans);
            }
            else 
            {
                //scanf("%d", &k); 
                k = Read();
                add(++n, k ^ ans);
            }
        }
        // puts("");
    }
}

发表评论

邮箱地址不会被公开。 必填项已用*标注