【倍增+线性基】2013.「SCOI2016」幸运数字

 

#2013.「SCOI2016」幸运数字

内存限制:256 MiB时间限制:4000 ms标准输入输出

题目描述

A 国共有座城市,这些城市由 n-1 条道路相连,使得任意两座城市可以互达,且路径唯一。每座城市都有一个幸运数字,以纪念碑的形式矗立在这座城市的正中心,作为城市的象征。一些旅行者希望游览 A 国。旅行者计划乘飞机降落在号城市,沿着号城市到号城市之间那条唯一的路径游览,最终从城市起飞离开 A 国。

在经过每一座城市时,游览者就会有机会与这座城市的幸运数字拍照,从而将这份幸运保存到自己身上。然而,幸运是不能简单叠加的,这一点游览者也十分清楚。他们迷信着幸运数字是以异或的方式保留在自己身上的。例如,游览者拍了张照片,幸运值分别是5、7、11,那么最终保留在自己身上的幸运值就是9(5^7^11)。

有些聪明的游览者发现,只要选择性地进行拍照,便能获得更大的幸运值。例如在上述三个幸运值中,只选择5 和11 ,可以保留的幸运值为14。现在,一些游览者找到了聪明的你,希望你帮他们计算出在他们的行程安排中可以保留的最大幸运值是多少。

输入格式

第一行包含两个正整数n、q,分别表示城市的数量和旅行者数量。
第二行包含个非负整数,其中第i个整数表示i号城市的幸运值。随后n-1行,每行包含两个正整数u,v,表示u号城市和v号城市之间有一条道路相连。
随后q行,每行包含两个正整数x、y,表示这名旅行者的旅行计划是从x号城市到y号城市。

输出格式

输出需要包含行,每行包含个非负整数,表示这名旅行者可以保留的最大幸运值。

样例

样例输入

4 2
11 5 7 9
1 2
1 3
1 4
2 3
1 4

样例输出

14
11

数据范围与提示

 

N≤2∗1e4
M≤2∗1e5
Ai≤2e60

 

倍增+线性基,在倍增的同时维护线性基,并且合并

F【i】【j】:第i个节点向上走2^j个节点的线性基

下附线性基板子:

struct L_B {
    long long d[61], p[61];
    int cnt;
    L_B() {
        memset(d, 0, sizeof(d));
        memset(p, 0, sizeof(p));
        cnt = 0;
    }

    bool Insert(long long val) {
        for (int i = 60; i >= 0; i--) {
            if (val & (1LL << i)) {
                if (!d[i]) {
                    d[i] = val;
                    break;
                }
                val ^= d[i];
            }
        }
        return val > 0;
    }

    long long query_max() {
        long long ret = 0;
        for (int i = 60; i >= 0; i--) {
            if ((ret ^ d[i]) > ret)
                ret ^= d[i];
        }
        return ret;
    }

    long long query_min() {
        for (int i = 0; i <= 60; i++) {
            if (d[i])
                return d[i];
        }
        return 0;
    }

    void rebuild() {
        for (int i = 60; i >= 0; i--) {
            for (int j = i - 1; j >= 0; j--) {
                if (d[i] & (1LL << j)) {
                    d[i] ^= d[j];
                }
            }
        }
        for (int i = 0; i <= 60; i++) {
            if (d[i]) {
                p[cnt++] = d[i];
            }
        }
    }

    long long kthquery(long long k) {
        long long ret = 0;
        if (k >= (1LL << cnt)) {
            return -1;
        }
        for (int i = 60; i >= 0; i--) {
            if (k & (1LL << i)) {
                ret ^= p[i];
            }
        }
        return ret;
    }
};
//将一个线性基暴力插入另一个线性基即可
void Merge(L_B &F, L_B &G) {
    for (int i = 60; i>=0; i --)
        if (G.d[i]) F.Insert(G.d[i]);
}
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=2e5+10;
ll a[maxn];
int n;
vector <int> G[maxn];
int fa[20005][16],dep[20005];

struct L_B{
    long long d[61];
    L_B()
    {
        memset(d, 0, sizeof(d));
    }

    bool Insert(long long val)
    {
        for(int i = 60; i >= 0; i--)
        {
            if(val & (1LL << i))
            {
                if(!d[i])
                {
                    d[i] = val;
                    break;
                }
                val ^= d[i];
            }
        }
        return val > 0;
    }

    long long query_max()
    {
        long long ret = 0;
        for(int i = 60;i >= 0; i--)
        {
            if((ret ^ d[i]) > ret)
                ret ^= d[i];
        }
        return ret;
    }
}F[20005][16],Ans;

//将一个线性基暴力插入另一个线性基即可
void Merge(L_B &F, L_B &G) {
    for (int i = 60; i>=0; i --)
        if (G.d[i]) F.Insert(G.d[i]);
}

void dfs(int u,int pre)
{
    dep[u]=dep[pre]+1;
    fa[u][0]=pre;
    for(auto x:G[u])
    {
        if(x==pre) continue;
        dfs(x,u);
    }
}

void Prepare()
{
	for (int j=1; j<=15; j++)
    {
        for(int i=1; i<=n; i++)
        {
            fa[i][j]=fa[fa[i][j - 1]][j - 1];
            for(int k=60;k>=0;k--)
            {
                F[i][j].d[k]=F[i][j-1].d[k];
            }
            Merge(F[i][j],F[fa[i][j-1]][j-1]);
        }
    }

}

void lca(int a,int b)
{
    if(dep[a]<dep[b]) swap(a,b);
    int d=dep[a]-dep[b];
    for(int i=0;(1<<i)<=d;i++)
    {
        if((1<<i)&d)
        {
            Merge(Ans,F[a][i]);
            a=fa[a][i];
        }
    }
    if(a==b)
    {
        Merge(Ans,F[a][0]);
        return;
    }
    for(int i=15;i>=0;i--)
    {
        if(fa[a][i]!=fa[b][i])
        {
            Merge(Ans, F[a][i]);
            Merge(Ans, F[b][i]);
            a=fa[a][i];
            b=fa[b][i];
        }
    }
    //~~!!!!特别重要啊!!!!
    Merge(Ans,F[a][0]);
    Merge(Ans,F[b][0]);
    Merge(Ans,F[fa[a][0]][0]);
}


int main()
{
    int Q,u,v;
    scanf("%d%d",&n,&Q);

    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
        F[i][0].Insert(a[i]);
    }

    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&u,&v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    dfs(1,0);//得到第i个节点的深度和父亲
    Prepare();//维护F[i][j]

    while(Q--)
    {
        for(int i=60;i>=0;i--)
            Ans.d[i]=0; //清空Ans线性基
        scanf("%d%d",&u,&v);
        lca(u,v);
        printf("%lld\n",Ans.query_max());
    }

    return 0;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言是一种广泛使用的编程语言,它具有高效、灵活、可移植性强等特点,被广泛应用于操作系统、嵌入式系统、数据库、编译器等领域的开发。C语言的本语法包括变量、数据类型、运算符、控制结构(如if语句、循环语句等)、函数、指针等。在编写C程序时,需要注意变量的声明和定义、指针的使用、内存的分配与释放等问题。C语言中常用的数据结构包括: 1. 数组:一种存储同类型数据的结构,可以进行索引访问和修改。 2. 链表:一种存储不同类型数据的结构,每个节点包含数据和指向下一个节点的指针。 3. 栈:一种后进先出(LIFO)的数据结构,可以通过压入(push)和弹出(pop)操作进行数据的存储和取出。 4. 队列:一种先进先出(FIFO)的数据结构,可以通过入队(enqueue)和出队(dequeue)操作进行数据的存储和取出。 5. 树:一种存储具有父子关系的数据结构,可以通过中序遍历、前序遍历和后序遍历等方式进行数据的访问和修改。 6. 图:一种存储具有节点和边关系的数据结构,可以通过广度优先搜索、深度优先搜索等方式进行数据的访问和修改。 这些数据结构在C语言中都有相应的实现方式,可以应用于各种不同的场景。C语言中的各种数据结构都有其优缺点,下面列举一些常见的数据结构的优缺点: 数组: 优点:访问和修改元素的速度非常快,适用于需要频繁读取和修改数据的场合。 缺点:数组的长度是固定的,不适合存储大小不固定的动态数据,另外数组在内存中是连续分配的,当数组较大时可能会导致内存碎片化。 链表: 优点:可以方便地插入和删除元素,适用于需要频繁插入和删除数据的场合。 缺点:访问和修改元素的速度相对较慢,因为需要遍历链表找到指定的节点。 栈: 优点:后进先出(LIFO)的特性使得栈在处理递归和括号匹配等问题时非常方便。 缺点:栈的空间有限,当数据量较大时可能会导致栈溢出。 队列: 优点:先进先出(FIFO)的特性使得
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果础还行,也可在此代码础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果础还行,也可在此代码础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果础还行,也可在此代码础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果础还行,也可在此代码础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值