• [SCOI2016] 幸运数字


    Description

    给定一棵树,每个点有点权。每次询问两个点 (x,y),求 (x)(y) 的路径上选择若干个点的点权异或和最大值。(nleq 2cdot 10^4,qleq 2cdot 10^5)

    Solution

    这种树上路径的题一般就是树剖啊点分治啊倍增啊。

    这题显然要维护线性基,线性基合并最低复杂度 (log^2n)

    如果树剖或者倍增维护线性基都是 (qlog^3 n) 的,但是都可以在线。

    但是如果换成点分治做就是 (qlog^2 n) 十分优秀。

    每次求出重心到每个点的线性基,只统计过重心的路径的答案即可。

    如果一条路径只经过了一个点特判掉即可。

    Code

    #include<bits/stdc++.h>
    using std::min;
    using std::max;
    using std::swap;
    using std::vector;
    typedef double db;
    typedef long long ll;
    #define pb(A) push_back(A)
    #define pii std::pair<int,int>
    #define all(A) A.begin(),A.end()
    #define mp(A,B) std::make_pair(A,B)
    #define int long long
    const int B=62;
    const int N=20005;
    
    vector< pii > v[N];
    int head[N],mx[N],vis[N],ok[N],val[N];
    int n,m,cnt,tot,root,id,MX,sze[N],ans[N*10];
    
    struct Edge{
        int to,nxt;
    }edge[N<<1];
    
    void add(int x,int y){
        edge[++cnt].to=y;
        edge[cnt].nxt=head[x];
        head[x]=cnt;
    }
    
    struct xxj{
        int a[B];
    
        xxj(){memset(a,0,sizeof a);}
    
        void clear(){memset(a,0,sizeof a);}
    
        void ins(int x){
            for(int i=61;~i;i--){
                if(x>>i&1){
                    if(!a[i]){
                        a[i]=x;
                        return;
                    } else x^=a[i];
                }
            }
        }
    
    }f[N];
    
    xxj hb(xxj a,xxj b){
        xxj c=a;
        for(int i=61;~i;i--)
            if(b.a[i]) c.ins(b.a[i]);
        return c;
    }
    
    void getroot(int now,int fa=0){
        mx[now]=0;sze[now]=1;
        for(int i=head[now];i;i=edge[i].nxt){
            int to=edge[i].to;
            if(vis[to] or to==fa) continue;
            getroot(to,now);sze[now]+=sze[to];
            mx[now]=max(mx[now],sze[to]);
        }  mx[now]=max(mx[now],tot-sze[now]);
        if(mx[now]<MX) MX=mx[now],root=now;
    }
    
    int getint(){
        int X=0,w=0;char ch=getchar();
        while(!isdigit(ch))w|=ch=='-',ch=getchar();
        while( isdigit(ch))X=X*10+ch-48,ch=getchar();
        if(w) return -X;return X;
    }
    
    int query(xxj a,int now=0){
        for(int i=61;~i;i--)
            if((now^a.a[i])>now)  
                now^=a.a[i];
        return now;
    }
    
    void dfs(int now,int fa){
        f[now]=f[fa];f[now].ins(val[now]);
        for(auto x:v[now]){
            if(ok[x.first]==id){
                xxj c=hb(f[now],f[x.first]);viss[x.second]=1;
                ans[x.second]=max(ans[x.second],query(c));
            }
        }
        for(int i=head[now];i;i=edge[i].nxt){
            int to=edge[i].to;
            if(!vis[to] and to!=fa)
                dfs(to,now);
        }
    }
    
    void upd(int now,int fa){
        ok[now]=id;
        for(int i=head[now];i;i=edge[i].nxt){
            int to=edge[i].to;
            if(!vis[to] and to!=fa)
                upd(to,now);
        }
    }
    
    void solve(int now){
        vis[now]=1;id=now;ok[now]=id;
        f[now].clear();f[now].ins(val[now]);
        for(int i=head[now];i;i=edge[i].nxt){
            int to=edge[i].to;
            if(!vis[to])
                dfs(to,now),upd(to,now);
        }
        for(int i=head[now];i;i=edge[i].nxt){
            int to=edge[i].to;
            if(!vis[to]){
                tot=sze[to];MX=1e9;
                getroot(to,0);solve(root);
            }
        }
    }
    
    signed main(){
        n=getint(),m=getint();
        for(int i=1;i<=n;i++) val[i]=getint();
        for(int i=1;i<n;i++){
            int x=getint(),y=getint();
            add(x,y),add(y,x);
        }
        for(int i=1;i<=m;i++){
            int x=getint(),y=getint();
            if(x==y) ans[i]=val[x];
            else v[x].pb(mp(y,i)),v[y].pb(mp(x,i));
        }
        tot=n,MX=1e9;getroot(1,0);
        solve(root);
        for(int i=1;i<=m;i++) 
            printf("%lld
    ",ans[i]);
        return 0;
    }
    
    
    
    
  • 相关阅读:
    微软职位内部推荐-SOFTWARE ENGINEER II
    微软职位内部推荐-SOFTWARE ENGINEER II
    微软职位内部推荐-SDEII for Windows Phone Apps
    微软职位内部推荐-SDEII for Windows Phone Apps
    微软职位内部推荐-Software Engineer II-SDP
    微软职位内部推荐-SDE II
    微软职位内部推荐-Senior Software Engineer-SDP
    微软职位内部推荐-Senior Software Engineer
    微软职位内部推荐-Software Engineer II-Office Incubation
    微软职位内部推荐-Senior Software Engineer-Office Incubation
  • 原文地址:https://www.cnblogs.com/YoungNeal/p/10216432.html
Copyright © 2020-2023  润新知