2019杭電多校第一場 HDU 6579

在這裏插入圖片描述

題意

給出一個初始序列,兩種操作,一種是詢問一個區間異或最大值,另一種是在序列末尾加一個數,強制在線。

題解

區間異或最大值要用線性基,考慮線段樹套線性基
空間複雜度爲O(nlog2n)O(n\cdot log^2n),又因爲線性基合併爲O(log2n)O(log^2n),所以時間複雜度爲O(nlog3n)O(n\cdot log^3n)
無法解決
考慮分塊,256個數字爲一個塊,每個塊建立一個線性基,並用pre[i]pre[i]las[i]las[i]分別維護塊內的前綴線性基和後綴線性基
用ST表維護一段區間的線性基
當詢問 [l,r][l,r] 時,找到所屬的塊[bl,br][bl,br]
如果bl=brbl=br,則在[l,r][l,r] 暴力建立線性基
否則,ST表找到[bl+1,br1][bl+1,br-1]的線性基,再與pre[r]pre[r]las[l]las[l]合併,就得到這段區間的線性基了
可以證明,空間和時間複雜度均爲O(nlog2n)O(n\cdot log^2n),實際更小

代碼

#include<bits/stdc++.h>
#define N 1000010
#define INF 0x3f3f3f3f
#define eps 1e-10
#define pi 3.141592653589793
#define P 1000000007
#define LL long long
#define pb push_back
#define fi first
#define se second
#define cl clear
#define si size
#define lb lower_bound
#define ub upper_bound
#define mem(x) memset(x,0,sizeof x)
#define sc(x) scanf("%d",&x)
#define scc(x,y) scanf("%d%d",&x,&y)
#define sccc(x,y,z) scanf("%d%d%d",&x,&y,&z)
using namespace std;

struct LB {
    int a[30];

    inline void clr() {
        memset(a, 0, sizeof a);
    }

    inline void ins(int x,int lim=29) {
        for (int i = lim; ~i; --i) {
            if (x >> i & 1) {
            if (!a[i]) { a[i] = x; return; }
            x ^= a[i];
            }
        }
    }

    inline int query() {
        int res = 0;
        for (int i = 29; ~i; --i) 
            if ((res ^ a[i]) > res) res ^= a[i];
        return res;
    }

    inline friend LB operator + (LB A,LB B) {
        for (int i = 29; ~i; --i) 
            if (B.a[i]) A.ins(B.a[i], i);
        return A;
    }
} f[3915][12],pre[N],las[N];

int a[N],lg[N];

LB query(int l,int r){
    if (l==r) return f[r][0];
    int t=lg[r-l];
    return f[r][t]+f[l+(1<<t)-1][t];
}
namespace IO{ 
    #define BUF_SIZE 100000 
    #define OUT_SIZE 100000 
    #define ll long long 
    bool IOerror=0; 
    inline char nc(){ 
        static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE; 
        if (p1==pend){ 
            p1=buf; pend=buf+fread(buf,1,BUF_SIZE,stdin); 
            if (pend==p1){IOerror=1;return -1;} 
        } 
        return *p1++; 
    } 
    inline bool blank(char ch){return ch==' '||ch=='\n'||ch=='\r'||ch=='\t';} 
    inline void read(int &x){ 
        bool sign=0; char ch=nc(); x=0; 
        for (;blank(ch);ch=nc()); 
        if (IOerror)return; 
        if (ch=='-')sign=1,ch=nc(); 
        for (;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0'; 
        if (sign)x=-x; 
    } 
};
using namespace IO;
int main(){
    int T,n,m;
    read(T);
    for (int i=2;i<N;i<<=1) lg[i]=1; for(int i=1;i<N;i++) lg[i]+=lg[i-1];
    while(T--){
        read(n);read(m); int ans=0,cnt=0;
        for(int i=1;i<=n;i++) read(a[i]);
        for(int i=0;i+255<=n;i+=256){
            f[++cnt][0].clr(); LB x; x.clr();
            for (int j=0;j<256;j++) f[cnt][0].ins(a[i+j]),pre[i+j]=f[cnt][0];
            for (int j=255;~j;--j) x.ins(a[i+j]),las[i+j]=x;
        }
        if ((n&255)!=255){
            int t=n;
            while(t&255) t--; 
            pre[t].clr(); pre[t].ins(a[t]);
            for(int i=t+1;i<=n;i++)
                pre[i]=pre[i-1],pre[i].ins(a[i]);
        }
          
        for (int j=1;j<=lg[cnt];j++)
            for(int i=1;i<=cnt;i++) if (i-(1<<j)+1>0)
                f[i][j]=f[i][j-1]+f[i-(1<<j-1)][j-1];

        while(m--){
            int op,l,r;
            read(op);
            if (!op){
                read(l);read(r);
                l=(l^ans)%n+1;r=(r^ans)%n+1; if (l>r) swap(l,r);
                int bl=(l>>8)+1,br=(r>>8)+1; LB x; x.clr();
                if (bl==br){
                    for (int i=l;i<=r;i++) x.ins(a[i]);
                    ans=x.query();
                    printf("%d\n",ans);
                }else{
                    if (bl+1!=br) x=query(bl+1,br-1);
                    x=x+las[l]; x=x+pre[r];
                    ans=x.query();
                    printf("%d\n",ans);
                }
            } else {
                read(r); r=r^ans;
                a[++n]=r; 
                if ((n&255)==0) 
                    pre[n].clr();
                else 
                    pre[n]=pre[n-1];
                pre[n].ins(a[n]);
                
                if ((n&255)==255){
                    f[++cnt][0].clr();
                    for(int i=0;i<256;i++) f[cnt][0].ins(a[n-i]),las[n-i]=f[cnt][0];
                    for(int i=1;i<12;i++) if (cnt-(1<<i)+1>0)
                        f[cnt][i]=f[cnt][i-1]+f[cnt-(1<<i-1)][i-1];
                }
            }
        }
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章