[SCOI2016]幸运数字

[SCOI2016]幸运数字

这其实就是把线性基搬到了树上,其实很简单.

因为线性基显然可以合并,所以直接用线段树维护即可.

套一个树剖,维护这棵维护线性基的线段树就好了.

问题只有一个字 \(:\)\(!\)

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC target("sse,sse2,sse3,sse4.1,sse4.2,popcnt,abm,mmx,avx")
#pragma comment(linker,"/STACK:102400000,102400000")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <string>
#include <vector>
#include <queue>
#include <cmath>
#include <ctime>
#include <map>
#include <set>
#define MEM(x,y) memset ( x , y , sizeof ( x ) )
#define rep(i,a,b) for (int i = (a) ; i <= (b) ; ++ i)
#define per(i,a,b) for (int i = (a) ; i >= (b) ; -- i)
#define pii pair < int , int >
#define one first
#define two second
#define rint read<int>
#define rll read<LL>
#define LL long long
#define pb push_back
#define db double
#define ull unsigned long long
#define lowbit(x) ( x & ( - x ) )

using std::queue ;
using std::set ;
using std::pair ;
using std::max ;
using std::min ;
using std::priority_queue ;
using std::vector ;
using std::swap ;
using std::sort ;
using std::unique ;
using std::greater ;

template < class T >
    inline T read () {
        T x = 0 , f = 1 ; char ch = getchar () ;
        while ( ch < '0' || ch > '9' ) {
            if ( ch == '-' ) f = - 1 ;
            ch = getchar () ;
        }
       while ( ch >= '0' && ch <= '9' ) {
            x = ( x << 3 ) + ( x << 1 ) + ( ch - 48 ) ;
            ch = getchar () ;
       }
       return f * x ;
    }

const int BITs = 65 ;
const int N = 2e4 + 100 ;

class LinearBasis {
    public : LL base[BITs] ;
    public :
        inline void clear () { MEM ( base , 0ll ) ; return ; }
    public :
        inline void insert (LL x) {
            if ( ! x ) return ;
            for (int i = 62 ; ~ i ; -- i)
                if ( x & ( 1ll << i ) ) {
                    if ( base[i] ) x ^= base[i] ;
                    else { base[i] = x ; return ; }
                }
            return ;
        }
    public :
        inline LL query () {
            LL res = 0ll ;
            for (int i = 62 ; ~ i ; -- i)
                res = max ( res , res ^ base[i] ) ;
            return res ;
        }
} ;

struct edge { int to , next ; } e[N<<1] ;

int tot , head[N] ;
int n , q , f[N] , deep[N] , siz[N] ;
int son[N] , idx[N] , ind , top[N] ;
LL v[N] , val[N] ;

inline LinearBasis merge (LinearBasis a , LinearBasis b) {
    LinearBasis res = a ;
    for (int i = 62 ; ~ i ; -- i) if ( b.base[i] ) res.insert ( b.base[i] ) ;
    return res ;
}

class segment {

    #define mid ( ( l + r ) >> 1ll )

    private : struct seg { int ls , rs ; LinearBasis data ; } t[N<<1] ;

    private : int cnt ;

    public : inline void clear () { cnt = 1ll ; return ; }

    public :
        inline void pushup (int rt) { t[rt].data = merge ( t[t[rt].ls].data , t[t[rt].rs].data ) ; return ; }

    public :
        inline void build (int rt , int l , int r) {
            if ( l == r ) { t[rt].data.clear () ; t[rt].data.insert ( v[l] ) ; return ; }
            t[rt].ls = ++ cnt ; build ( t[rt].ls , l , mid ) ;
            t[rt].rs = ++ cnt ; build ( t[rt].rs , mid + 1 , r ) ;
            pushup ( rt ) ; return ;
        }

    public :
        inline LinearBasis query (int rt , int l , int r , int ll , int rr) {
            if ( ll == l && r == rr ) return t[rt].data ;
            if ( rr <= mid ) return query ( t[rt].ls , l , mid , ll , rr ) ;
            else if ( ll > mid ) return query ( t[rt].rs , mid + 1 , r , ll , rr ) ;
            else return merge ( query ( t[rt].ls , l , mid , ll , mid ) , query ( t[rt].rs , mid + 1 , r , mid + 1 , rr ) ) ;
        }

    #undef mid

} T ;

inline void build (int u , int v) { e[++tot].next = head[u] ; e[tot].to = v ; head[u] = tot ; return ; }

inline void dfs (int cur , int anc , int dep) {
    f[cur] = anc ; deep[cur] = dep ; siz[cur] = 1 ;
    int maxson = - 1 ;
    for (int i = head[cur] ; i ; i = e[i].next){
        int k = e[i].to ; if ( k == anc ) continue ;
        dfs ( k , cur , dep + 1 ) ; siz[cur] += siz[k] ;
        if ( siz[k] > maxson ) maxson = siz[k] , son[cur] = k ;
    }
    return ;
}

inline void _dfs (int cur , int topf) {
    top[cur] = topf ; idx[cur] = ++ ind ; v[ind] = val[cur] ;
    if ( ! son[cur] ) return ; _dfs ( son[cur] , topf ) ;
    for (int i = head[cur] ; i ; i = e[i].next){
        int k = e[i].to ;
        if ( k == f[cur] || k == son[cur] ) continue ;
        _dfs ( k , k ) ;
    }
    return ;
}

inline LL qrange (int x , int y) {
    LinearBasis res ; res.clear () ;
    while ( top[x] != top[y] ) {
        if ( deep[top[x]] < deep[top[y]] ) swap ( x , y ) ;
        res = merge ( res , T.query ( 1 , 1 , ind , idx[top[x]] , idx[x] ) ) ;
        x = f[top[x]] ;
    }
    if ( deep[x] > deep[y] ) swap ( x , y ) ;
    res = merge ( res , T.query ( 1 , 1 , ind , idx[x] , idx[y] ) ) ;
    return res.query () ;
}

int main () {
    n = rint () ; q = rint () ;
    rep ( i , 1 , n ) val[i] = rll () ;
    rep ( i , 2 , n ) {
        int x = rint () , y = rint () ;
        build ( x , y ) ; build ( y , x ) ;
    }
    dfs ( 1 , 0 , 1 ) ; _dfs ( 1 , 1 ) ;
    T.clear () ; T.build ( 1 , 1 , ind ) ;
    while ( q -- ) {
        int x = rint () , y = rint () ;
        printf ("%lld\n" , qrange ( x , y ) ) ;
    }
    return 0 ;
}

这种写法可能会很慢,因为它是三个 \(log\) 的.

所以需要卡卡常.

问题不大.

还可以用倍增去做,能消掉一个 \(log\).

具体实现就不说了,应该很简单.

posted @ 2019-10-25 11:07  Phecda  阅读(108)  评论(0编辑  收藏  举报

Contact with me