zoukankan      html  css  js  c++  java
  • bzoj4568: [Scoi2016]幸运数字

    树上倍增维护线性基。

    一开始以为有什么奥妙,然而并没有。

    暴力倍增地维护某点往上2^j个父亲的线性基就好了。合并线性基的时候就暴力把一个往另一个里插。

    就是跑得很慢,可能太暴力了。

    终于写完scoi2016啦。

    //Achen
    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<vector>
    #include<cstdio>
    #include<queue>
    #include<cmath>
    const int N=40007;
    typedef long long LL;
    using namespace std;
    int n,q;
    LL a[N],d[N],power[61];
    
    template<typename T>void read(T &x)  {
        char ch=getchar(); x=0; T f=1;
        while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
        if(ch=='-') f=-1,ch=getchar();
        for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
    }
    
    int ecnt,fir[N],nxt[N],to[N];
    void add(int u,int v) {
        nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v;
        nxt[++ecnt]=fir[v]; fir[v]=ecnt; to[ecnt]=u;
    }
    
    void insert(LL x,LL d[]) {
        for(int i=60;i>=0;i--) if(x&power[i]) {
            if(!d[i]) {d[i]=x; break;}
            else x^=d[i];
        }
    }
    
    int f[20003][15],R[N];
    LL b[20003][15][61];
    void dfs(int x,int fa) {
        f[x][0]=fa; R[x]=R[fa]+1;
        insert(a[x],b[x][0]); insert(a[f[x][0]],b[x][0]);
        for(int i=1;i<15;i++) {
            f[x][i]=f[f[x][i-1]][i-1];
            if(R[x]-power[i]<=0) break;
            for(int j=0;j<=60;j++) b[x][i][j]=b[x][i-1][j];
            for(int j=0;j<=60;j++) 
                insert(b[f[x][i-1]][i-1][j],b[x][i]);
        }
        for(int i=fir[x];i;i=nxt[i]) if(to[i]!=fa) {
            dfs(to[i],x);
        }
    }
    
    LL qry() {
        LL res=0;
        for(int i=60;i>=0;i--)
            if((res^d[i])>res) res=res^d[i];
        return res;
    }
    
    LL get_ans(int x,int y) {
        for(int i=0;i<=60;i++) d[i]=0;
        insert(a[x],d); insert(a[y],d);
        if(R[x]<R[y]) swap(x,y);
        for(int i=14;i>=0;i--) 
            if(R[f[x][i]]>=R[y]) {
                for(int j=0;j<=60;j++)
                    insert(b[x][i][j],d);
                x=f[x][i];
            }
        for(int i=14;i>=0;i--) 
            if(f[x][i]!=f[y][i]) {
                for(int j=0;j<=60;j++) {
                    insert(b[x][i][j],d);
                    insert(b[y][i][j],d);
                }
                x=f[x][i]; y=f[y][i];
            }
        if(x!=y) {
            x=f[x][0];
            insert(a[x],d);
        }
        return qry();
    }
    
    int main() {
        read(n); read(q);
        for(int i=1;i<=n;i++) read(a[i]);
        for(int i=1;i<n;i++) {
            int u,v;
            read(u); read(v);
            add(u,v);
        }
        power[0]=1;
        for(int i=1;i<=60;i++) power[i]=power[i-1]*2;
        dfs(1,0);
        while(q--) {
            int x,y;
            read(x); read(y);
            printf("%lld
    ",get_ans(x,y));
        }
        return 0;
    }
    /*
    5 1
    4 5 4 9 10 
    2 1
    3 2
    4 1
    5 3
    4 5
    */
    View Code
  • 相关阅读:
    课堂练习求环整数组中最大子数组之和
    学习进度第7周
    声明
    最大数
    学习进度02
    构建之法阅读笔记02
    学习进度01
    课堂练习之《哈利波特》
    《构建之法》阅读笔记06
    寻找水龙王2
  • 原文地址:https://www.cnblogs.com/Achenchen/p/8407079.html
Copyright © 2011-2022 走看看