题目描述

A 国共有 n 座城市,这些城市由 n-1 条道路相连,使得任意两座城市可以互达,且路径唯一。每座城市都有一个幸运数字,以纪念碑的形式矗立在这座城市的正中心,作为城市的象征。

一些旅行者希望游览 A 国。旅行者计划乘飞机降落在 x 号城市,沿着 x 号城市到 y 号城市之间那条唯一的路径游览,最终从 y 城市起飞离开 A 国。在经过每一座城市时,游览者就会有机会与这座城市的幸运数字拍照,从而将这份幸运保存到自己身上。然而,幸运是不能简单叠加的,这一点游览者也十分清 楚。他们迷信着幸运数字是以异或的方式保留在自己身上的。

例如,游览者拍了 3 张照片,幸运值分别是 5,7,11,那么最终保留在自己身上的幸运值就是 9(5 xor 7 xor 11)。

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

输入输出格式

输入格式:

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

输出格式:

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

输入输出样例

输入样例#1:

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

输出样例#1:

14
11

我们每次找到重心,处理与重心相关的路径。

处理时我们将重心到每个节点这一段的线性基存起来,然后找到所有经过重心的路径

在遍历以重心G为根的一个子树过程中,找到与这棵子树中节点u有关的询问(u,v),判断是否在之前遍历过的以重心为根的其他子树中出现过,如果出现过,我们可以将G->u和G->v的线性基合并

找到合并后的线性基中的最大值就好了。对于合并,直接暴力拆开一个线性基,一个一个插入到另一个线性基中

处理完这棵子树之后,再遍历一遍,打上访问过的标记。这样保证所有询问都只计算过一次。

注意,处理完这个重心之后,清空标记时,不要memset,直接再遍历一遍就好了,快得多。

值得注意的是,要单独考虑与G有关的询问如(G,v)

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<cmath>
  6 using namespace std;
  7 typedef long long lol;
  8 struct Node
  9 {
 10   int next,to,dis;
 11 }edge[40001],edgeq[400001];
 12 int num,numq,head[20001],headq[200001];
 13 int size[20001],maxsize[20001],minsize,root,n,q;
 14 bool vis[20001],judge[20001];
 15 lol ans[200001],pw[64],val[20001];
 16 struct BASE
 17 {
 18   lol a[64];
 19   void clear()
 20   {
 21     for (int i=0;i<=62;i++)
 22       a[i]=0;
 23   }
 24   void insert(lol x)
 25   {
 26     for (int i=62;i>=0;i--)
 27       {
 28     if (x&pw[i])
 29       {
 30         if (a[i]==0)
 31           {a[i]=x;break;}
 32         else x^=a[i];
 33       }
 34       }
 35   }
 36   lol getmax()
 37   {
 38     lol x=0;
 39     for (int i=62;i>=0;i--)
 40       {
 41     if ((x^a[i])>x)
 42       x^=a[i];
 43       }
 44     return x;
 45   }
 46   void merge(BASE b)
 47   {
 48     for (int i=0;i<=62;i++)
 49       insert(b.a[i]);
 50   }
 51   void copy(BASE b)
 52   {
 53     for (int i=0;i<=62;i++)
 54       a[i]=b.a[i];
 55   }
 56 }base[20002];
 57 void add(int u,int v)
 58 {
 59   num++;
 60   edge[num].next=head[u];
 61   head[u]=num;
 62   edge[num].to=v;
 63 }
 64 void addq(int u,int v,int d)
 65 {
 66   numq++;
 67   edgeq[numq].next=headq[u];
 68   headq[u]=numq;
 69   edgeq[numq].to=v;
 70   edgeq[numq].dis=d;
 71 }
 72 void get_size(int x,int fa)
 73 {
 74   int i;
 75   size[x]=1;
 76   maxsize[x]=0;
 77   for (i=head[x];i;i=edge[i].next)
 78     {
 79       int v=edge[i].to;
 80       if (vis[v]==0&&v!=fa)
 81     {
 82       get_size(v,x);
 83       size[x]+=size[v];
 84       maxsize[x]=max(maxsize[x],size[v]);
 85     }
 86     }
 87 }
 88 void get_root(int r,int x,int fa)
 89 {
 90   int i;
 91   maxsize[x]=max(maxsize[x],size[r]-size[x]);
 92   if (maxsize[x]<minsize)
 93     {
 94       root=x;
 95       minsize=maxsize[x];
 96     }
 97   for (i=head[x];i;i=edge[i].next)
 98     {
 99       int v=edge[i].to;
100       if (vis[v]==0&&v!=fa)
101     {
102       get_root(r,v,x);
103     }
104     }
105 }
106 void get_ans(int r,int x,int fa)
107 {int i;
108   base[x].copy(base[fa]);
109   base[x].insert(val[x]);
110   for (i=headq[x];i;i=edgeq[i].next)
111     {
112       int v=edgeq[i].to;
113       if (judge[v])
114     {
115       BASE tmp;
116       tmp.copy(base[x]);
117       tmp.merge(base[v]);
118       ans[edgeq[i].dis]=tmp.getmax();
119     }
120       else if (v==r)
121     {
122       ans[edgeq[i].dis]=base[x].getmax();
123     }
124     }
125   for (i=head[x];i;i=edge[i].next)
126     {
127       int v=edge[i].to;
128       if (vis[v]==0&&v!=fa)
129     {
130       get_ans(r,v,x);
131     }
132     }
133 }
134 void get_update(int x,int fa)
135 {
136   judge[x]=!judge[x];
137   for (int i=head[x];i;i=edge[i].next)
138     {
139       int v=edge[i].to;
140       if (vis[v]==0&&v!=fa)
141     {
142       get_update(v,x);
143     }
144     }
145 }
146 void doit(int x)
147 {
148   minsize=2e9;
149   get_size(x,0);
150   get_root(x,x,0);
151   vis[root]=1;
152   base[root].clear();
153   base[root].insert(val[root]);
154   for (int i=head[root];i;i=edge[i].next)
155     {
156       int v=edge[i].to;
157       if (vis[v]==0)
158     {
159       get_ans(root,v,root);
160       get_update(v,root);
161     }
162     }
163     for (int i=head[root];i;i=edge[i].next)
164     {
165       int v=edge[i].to;
166       if (vis[v]==0)
167     {
168       get_update(v,root);
169     }
170     }
171  for (int i=head[root];i;i=edge[i].next)
172     {
173       int v=edge[i].to;
174       if (vis[v]==0)
175     {
176       doit(v);
177     }
178     }
179 }
180 int main()
181 {int i,u,v;
182   cin>>n>>q;
183   pw[0]=1;
184   for (i=1;i<=62;i++)
185     pw[i]=pw[i-1]*2;
186   for (i=1;i<=n;i++)
187     {
188       scanf("%lld",&val[i]);
189     }
190   for (i=1;i<=n-1;i++)
191     {
192       scanf("%d%d",&u,&v);
193       add(u,v);add(v,u);
194     }
195   for (i=1;i<=q;i++)
196     {
197       scanf("%d%d",&u,&v);
198       if (u!=v)
199     addq(u,v,i),addq(v,u,i);
200       else ans[i]=val[u];
201     }
202   doit(1);
203   for (i=1;i<=q;i++)
204     {
205       printf("%lld\n",ans[i]);
206     }
207 }

转载于:https://www.cnblogs.com/Y-E-T-I/p/7617591.html

[SCOI2016]幸运数字相关推荐

  1. Bzoj4568: [Scoi2016]幸运数字

    Bzoj4568: [Scoi2016]幸运数字 线性基+倍增+LCA 原来线性基还能这么考--一开始看到这个题以为是树上差分线性基,然而线性基不支持删除,所以就挂了. 后来想到倍增线性基,其实到这里 ...

  2. P3292 [SCOI2016]幸运数字(树剖 + 线段树维护线性基)

    P3292 [SCOI2016]幸运数字 思路 如果这题是求x,yx, yx,y之间的距离显然我们可以通过树剖加线段树来写, 但是这里变成了求任意个数的异或最大值.如果给定区间我们显然可以通过线性基来 ...

  3. [洛谷P3292] [SCOI2016]幸运数字

    洛谷题目链接:[SCOI2016]幸运数字 题目描述 A 国共有 n 座城市,这些城市由 n-1 条道路相连,使得任意两座城市可以互达,且路径唯一.每座城市都有一个幸运数字,以纪念碑的形式矗立在这座城 ...

  4. [BZOJ4568][SCOI2016]幸运数字(倍增LCA,点分治+线性基)

    4568: [Scoi2016]幸运数字 Time Limit: 60 Sec  Memory Limit: 256 MB Submit: 2131  Solved: 865 [Submit][Sta ...

  5. bzoj 4568: [Scoi2016]幸运数字(树上倍增+线性基)

    4568: [Scoi2016]幸运数字 Time Limit: 60 Sec  Memory Limit: 256 MB Submit: 1692  Solved: 643 [Submit][Sta ...

  6. BZOJ4568 [Scoi2016]幸运数字

    BZOJ4568 [Scoi2016]幸运数字 题目描述 传送门 题目分析 这个题,求树上链的\(XOR\)最大值,可以不选某些点. 考虑到线性基可以用很快的速度求出\(XOR\)的最大值,我们首先可 ...

  7. BZOJ4568:[SCOI2016]幸运数字——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=4568 https://www.luogu.org/problemnew/show/P3292 A ...

  8. [bzoj4568][Scoi2016]幸运数字

    来自FallDream的博客,未经允许,请勿转载,谢谢. A 国共有 n 座城市,这些城市由 n-1 条道路相连,使得任意两座城市可以互达,且路径唯一.每座城市都有一个幸运数字,以纪念碑的形式矗立在这 ...

  9. BZOJ4568: [Scoi2016]幸运数字(线性基 倍增)

    题意 题目链接 Sol 线性基是可以合并的 倍增维护一下 然后就做完了?? 喵喵喵? // luogu-judger-enable-o2 #include<bits/stdc++.h> # ...

最新文章

  1. 基于Python的验证码识别技术
  2. NLP模型超越人类水平?你可能碰到了大忽悠
  3. 可怕!如果张东升是个程序员......
  4. python官网下载步骤64位-电脑64位怎么下载python
  5. 机器学习中倒三角符号_机器学习的三角误差
  6. postmain请求中午乱码_完美解决Get和Post请求中文乱码的问题
  7. 剑指offer:18-21记录
  8. Liferay6.2.1 集成 CAS4.0 实现单点登录与应用系统集成
  9. it有啥好咨询的_小经验 | 埃森哲Accenture管理咨询+IT咨询实习
  10. Nemo(Nightwish乐队)
  11. 行为型设计模式(2)—— 模板方法模式(Template Method Pattern)
  12. python数据分析收获与心得体会_初次数据分析--我的心得体会
  13. Linux基础-分区规划与使用
  14. 全了!国内外知名互联网排名
  15. CUDA----.cpp文件和.cu文件应用区别
  16. openEuler基础(二十)用户创建、密码管理、用户锁定
  17. Java基础入门必须学好的英语词汇
  18. 使用树莓派搭建家用 NAS
  19. #define的定义用法
  20. Flip Flop和DoOnce

热门文章

  1. mysql根据id分页_MySQL_MSSQL根据ID进行分页实现方法,复制代码 代码如下: ALTER PROCEDU - phpStudy...
  2. 使用pandas读取excel
  3. Oracle数据库培训视频教程 oracle工程师培训视频教程
  4. GIt登录不了,报错:Whoops, something went wrong on our end.
  5. 二进制安全之NX绕过方法--ROP技术
  6. GD32F130之USART自带的RS485方向切换功能
  7. Windows10自带软件一款性能监控工具
  8. 树莓和Arduino之间的蓝牙通讯
  9. ASO优化之如何使用 Apple 活动功能及应用内事件 (IAE) 来提高您的自然可见度?
  10. 怎么批量修改html文件后缀,如何批量修改文件后缀名 超详细介绍