• SCOI2016 幸运数字


    题目链接:戳我

    不想说了......就树上的线性基合并.......

    但是讲道理O(nlogn^3)为什么能过去呢.......但是就是能过去啊,因为博主是菜鸡不怎么会淀粉质啊,所以本篇题解只能提供这个复杂度的算法了QAQ$$

    求选出来一些数使得异或和最大?线性基啊!那怎么求路径上的呢?一个一个往上合并,一直合并到LCA就行了吧!

    一个一个合并显然不行,我们考虑倍增。怎么倍增呢?就和LCA差不多......具体可以看一下代码。

    需要注意的是我们的(p[i][j])表示的是从这个点出发,往上面合并(2^j)个线性基的意思,所以(p[i][0])表示的是该点的线性基,所以倍增合并的时候,最后还要合并一下自己。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define MAXN 20010
    using namespace std;
    inline long long read()
    {
        long long 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<<1)+(x<<3)+(ch^48);ch=getchar();}
        return x*f;
    }
    int n,m,t;
    int fa[MAXN][16],dep[MAXN],head[MAXN];
    long long p[MAXN][16][62],sum[MAXN];
    struct Edge{int nxt,to;}edge[MAXN<<1];
    inline void add(int from,int to)
    {
        edge[++t].nxt=head[from],edge[t].to=to;
        head[from]=t;
    }
    inline void dfs(int x,int pre)
    {
        fa[x][0]=pre;
        dep[x]=dep[pre]+1;
        for(int i=head[x];i;i=edge[i].nxt)
        {
            int v=edge[i].to;
            if(v==pre) continue;
            dfs(v,x);
        }
    }
    inline void insert(long long *a,long long x)
    {
        for(int i=61;i>=0;i--)
        {
            if((x>>i)&1)
            {
                if(a[i]) x^=a[i];
                else {a[i]=x;break;}
            }
        }
    }
    inline void merge(long long *a,long long *b)
    {
        for(int i=61;i>=0;i--)
            if(b[i])
                insert(a,b[i]);
    }
    inline long long get_ans(long long *a)
    {
        long long cur_ans=0;
        for(int i=61;i>=0;i--)
            cur_ans=max(cur_ans,cur_ans^a[i]);
        return cur_ans;
    }
    inline void init()
    {
        for(int i=1;i<=n;i++) insert(p[i][0],sum[i]);
        // for(int i=1;i<=n;i++) printf("p[%d]=%lld
    ",i,get_ans(p[i][0]));
        for(int j=1;j<=15;j++)
        {
            for(int i=1;i<=n;i++)
            {
                fa[i][j]=fa[fa[i][j-1]][j-1];
                memcpy(p[i][j],p[i][j-1],sizeof(p[i][j-1]));
                merge(p[i][j],p[fa[i][j-1]][j-1]);
            }
        }
    }
    inline long long __lca(int x,int y)
    {
        long long ans[64];
        memset(ans,0,sizeof(ans));
        while(dep[x]!=dep[y])
        {
            if(dep[x]<dep[y]) swap(x,y);
            long long tt=dep[x]-dep[y];
            for(int j=61;j>=0;j--)
            {
                if(tt&(1ll<<j))
                {
                    merge(ans,p[x][j]);
                    x=fa[x][j];
                }
            }
        }
        if(x==y) 
        {
            merge(ans,p[x][0]);
            return get_ans(ans);
        }
        for(int i=15;i>=0;i--)
        {
            if(fa[x][i]!=fa[y][i])
            {
                merge(ans,p[x][i]),merge(ans,p[y][i]);
                x=fa[x][i],y=fa[y][i];
            }
        }
        merge(ans,p[x][0]),merge(ans,p[y][0]);
        merge(ans,p[fa[x][0]][0]);
        return get_ans(ans);
    }
    int main()
    {
        #ifndef ONLINE_JUDGE
        freopen("ce.in","r",stdin);
        freopen("ce.out","w",stdout);
        #endif
        n=read(),m=read();
        for(int i=1;i<=n;i++) sum[i]=read(); 
        for(int i=1;i<n;i++)
        {
            int x=read(),y=read();
            add(x,y),add(y,x);
        }
        dfs(1,0);
        init();
        // for(int i=1;i<=n;i++) printf("%lld
    ",get_ans(p[i][0]));
        for(int i=1;i<=m;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            printf("%lld
    ",__lca(x,y));
        }
        return 0;
    }
    
  • 相关阅读:
    C#——面向对象,常用类
    C#——基础
    C#——winform
    Oracle——PL/SQL,存储过程/函数,java连接Oracle操作存储过程/函数,触发器
    Oracle——数据处理(增删改查),创建表与管理表,视图,索引,同义词
    Oracle——集合运算
    PoisonTap
    在Ubuntu上安装LAMP(Apache、Mysql、Php)
    "Unable to locate package lrzsz"的解决办法
    OtterCTF
  • 原文地址:https://www.cnblogs.com/fengxunling/p/10888326.html
Copyright © 2020-2023  润新知