[BZOJ4568][SCOI2016]幸运数字(倍增LCA,点分治+线性基)
4568: [Scoi2016]幸运数字
Time Limit: 60 Sec Memory Limit: 256 MB
Submit: 2131 Solved: 865
[Submit][Status][Discuss]Description
A 国共有 n 座城市,这些城市由 n-1 条道路相连,使得任意两座城市可以互达,且路径唯一。每座城市都有一个幸运数字,以纪念碑的形式矗立在这座城市的正中心,作为城市的象征。一些旅行者希望游览 A 国。旅行者计划乘飞机降落在 x 号城市,沿着 x 号城市到 y 号城市之间那条唯一的路径游览,最终从 y 城市起飞离开 A 国。在经过每一座城市时,游览者就会有机会与这座城市的幸运数字拍照,从而将这份幸运保存到自己身上。然而,幸运是不能简单叠加的,这一点游览者也十分清楚。他们迷信着幸运数字是以异或的方式保留在自己身上的。例如,游览者拍了 3 张照片,幸运值分别是 5,7,11,那么最终保留在自己身上的幸运值就是 9(5 xor 7 xor 11)。有些聪明的游览者发现,只要选择性地进行拍照,便能获得更大的幸运值。例如在上述三个幸运值中,只选择 5和 11 ,可以保留的幸运值为 14 。现在,一些游览者找到了聪明的你,希望你帮他们计算出在他们的行程安排中可以保留的最大幸运值是多少。Input
第一行包含 2 个正整数 n ,q,分别表示城市的数量和旅行者数量。第二行包含 n 个非负整数,其中第 i 个整数 Gi 表示 i 号城市的幸运值。随后 n-1 行,每行包含两个正整数 x ,y,表示 x 号城市和 y 号城市之间有一条道路相连。随后 q 行,每行包含两个正整数 x ,y,表示这名旅行者的旅行计划是从 x 号城市到 y 号城市。N<=20000,Q<=200000,Gi<=2^60Output
输出需要包含 q 行,每行包含 1 个非负整数,表示这名旅行者可以保留的最大幸运值。
Sample Input
4 2
11 5 7 9
1 2
1 3
1 4
2 3
1 4Sample Output
14
11HINT
Source
线性基不支持删除,但是支持插入与合并,于是显然可以树剖维护,$O(n\log^4n)$。
线性基不支持修改,浪费了线段树支持修改的功能,实际上可以直接用不支持修改的ST表,$O(n\log^3n)$。
点分治不仅可以做路径统计问题,还可以处理与路径有关的询问问题,将每个询问的两个点的vector中放入这个询问,每次递归到一个重心时查找管辖范围内的所有询问,因为一个询问只涉及两个点,所以复杂度是有保证的。$O(n\log^2n)$
下面是倍增LCA的代码,要注意关于点的LCA和普通的是有区别的:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define rep(i,l,r) for (int i=l; i<=r; i++)
typedef long long ll;
using namespace std; const int N=,M=;
ll g[N][][M],Ans[M],a[N];
int n,Q,u,v,cnt,to[N<<],nxt[N<<],h[N],d[N],fa[N][]; void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; }
void ins(ll p[],ll x){
for (int i=; ~i; i--) if (x&(1ll<<i)){
if (!p[i]) { p[i]=x; break; } else x^=p[i];
}
}
void merge(ll g[],ll f1[],ll f2[]){
rep(i,,) g[i]=f1[i];
rep(i,,) if (f2[i]) ins(g,f2[i]);
}
void dfs(int x){
ins(g[x][],a[x]);
rep(i,,){
fa[x][i]=fa[fa[x][i-]][i-];
merge(g[x][i],g[x][i-],g[fa[x][i-]][i-]);
}
for (int i=h[x],k; i; i=nxt[i])
if ((k=to[i])!=fa[x][]) fa[k][]=x,d[k]=d[x]+,dfs(k);
} void lca(int u,int v){
memset(Ans,,sizeof(Ans));
if (d[u]<d[v]) swap(u,v);
int t=d[u]-d[v];
for (int i=; ~i; i--)
if (t&(<<i)) merge(Ans,Ans,g[u][i]),u=fa[u][i];
if (u==v){ merge(Ans,Ans,g[u][]); return; }
for (int i=; ~i; i--)
if (fa[u][i]!=fa[v][i])
merge(Ans,Ans,g[u][i]),merge(Ans,Ans,g[v][i]),
u=fa[u][i],v=fa[v][i];
merge(Ans,Ans,g[u][]); merge(Ans,Ans,g[v][]);
merge(Ans,Ans,g[fa[u][]][]);
} ll get(ll p[]){
ll res=;
for (int i=; ~i; i--) res=max(res,res^p[i]);
return res;
} int main(){
freopen("bzoj4568.in","r",stdin);
freopen("bzoj45682.out","w",stdout);
scanf("%d%d",&n,&Q);
rep(i,,n) scanf("%lld",&a[i]);
rep(i,,n) scanf("%d%d",&u,&v),add(u,v),add(v,u);
dfs();
while (Q--) scanf("%d%d",&u,&v),lca(u,v),printf("%lld\n",get(Ans));
return ;
}
然后是点分治,本机时间跑的是倍增的一半,交到OJ上就莫名其妙的死活TLE,弃疗。
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#define rep(i,l,r) for (int i=l; i<=r; i++)
#define For(i,x) for (int i=h[x],k; i; i=nxt[i])
typedef long long ll;
using namespace std; const int N=,M=,inf=;
int n,Q,u,v,cnt,S,rt,tim,pos[N],f[N],b[N],sz[N],vis[N],d[N];
int fa[N][],h[N],to[N<<],nxt[N<<];
ll a[N],g[N][],Ans[],ans[M];
struct P{ int u,v; }s[M];
vector<int>V[N];
void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; } void ins(ll p[],ll x){
for (int i=; ~i; i--) if (x&(1ll<<i)){
if (!p[i]) { p[i]=x; break; } else x^=p[i];
}
} void merge(ll g[],ll f1[],ll f2[]){
rep(i,,) g[i]=f1[i];
rep(i,,) if (f2[i]) ins(g,f2[i]);
} ll get(ll p[]){
ll res=;
for (int i=; ~i; i--) res=max(res,res^p[i]);
return res;
} void find(int x,int fa){
f[x]=; sz[x]=;
For(i,x) if ((k=to[i])!=fa && !vis[k])
find(k,x),sz[x]+=sz[k],f[x]=max(f[x],sz[k]);
f[x]=max(f[x],S-sz[x]);
if (f[x]<f[rt]) rt=x;
} void work(int x,int fa,int bel){
pos[x]=bel; b[x]=tim;
rep(i,,) g[x][i]=g[fa][i]; ins(g[x],a[x]);
For(i,x) if ((k=to[i])!=fa && !vis[k]) work(k,x,bel);
} void work1(int x,int fa){
for (vector<int>::iterator it=V[x].begin(); it!=V[x].end(); it++){
int k=*it; if (ans[k]) continue;
int u=s[k].u; if (u==x) u=s[k].v;
if (b[u]==tim && (pos[u]!=pos[x] || !pos[u]))
merge(Ans,g[u],g[x]),ans[k]=get(Ans);
}
For(i,x) if ((k=to[i])!=fa && !vis[k]) work1(k,x);
} void solve(int x){
vis[x]=; b[x]=++tim; pos[x]=;
rep(i,,) g[x][i]=; ins(g[x],a[x]);
For(i,x) if (!vis[k=to[i]]) work(k,x,k); work1(x,);
For(i,x) if (!vis[k=to[i]]) S=sz[k],f[rt=]=inf,find(k,x),solve(k);
} int main(){
freopen("bzoj4568.in","r",stdin);
freopen("bzoj4568.out","w",stdout);
scanf("%d%d",&n,&Q);
rep(i,,n) scanf("%lld",&a[i]);
rep(i,,n) scanf("%d%d",&u,&v),add(u,v),add(v,u);
rep(i,,Q) scanf("%d%d",&s[i].u,&s[i].v),V[s[i].u].push_back(i),V[s[i].v].push_back(i);
f[rt=]=inf; S=n; find(,); solve(rt);
rep(i,,Q) printf("%lld\n",ans[i]);
return ;
}
[BZOJ4568][SCOI2016]幸运数字(倍增LCA,点分治+线性基)的更多相关文章
- [BZOJ4568][Scoi2016]幸运数字 倍增+线性基
4568: [Scoi2016]幸运数字 Time Limit: 60 Sec Memory Limit: 256 MBSubmit: 1791 Solved: 685[Submit][Statu ...
- [SCOI2016]幸运数字 树链剖分,线性基
[SCOI2016]幸运数字 LG传送门 为了快乐,我们用树剖写这题. 强行树剖,线段树上每个结点维护一个线性基,每次查询暴力合并. 瞎分析一波复杂度:树剖两点之间\(\log n\)条重链,每条重链 ...
- 【BZOJ4568】[Scoi2016]幸运数字 倍增+线性基
[BZOJ4568][Scoi2016]幸运数字 Description A 国共有 n 座城市,这些城市由 n-1 条道路相连,使得任意两座城市可以互达,且路径唯一.每座城市都有一个幸运数字,以纪念 ...
- bzoj4568: [Scoi2016]幸运数字(LCA+线性基)
4568: [Scoi2016]幸运数字 题目:传送门 题解: 好题!!! 之前就看过,当时说是要用线性基...就没学 填坑填坑: %%%线性基 && 神犇 主要还是对于线性基的运用和 ...
- BZOJ4568 [Scoi2016]幸运数字 【点分治 + 线性基】
题目链接 BZOJ4568 题解 选任意个数异或和最大,使用线性基 线性基插入\(O(logn)\),合并\(O(log^2n)\) 我们要求树上两点间异或和最大值,由于合并是\(O(log^2n)\ ...
- 2019.03.25 bzoj4568: [Scoi2016]幸运数字(倍增+线性基)
传送门 题意:给你一棵带点权的树,多次询问路径的最大异或和. 思路: 线性基上树?? 倍增维护一下就完了. 时间复杂度O(nlog3n)O(nlog^3n)O(nlog3n) 代码: #include ...
- BZOJ4568: [Scoi2016]幸运数字(线性基 倍增)
题意 题目链接 Sol 线性基是可以合并的 倍增维护一下 然后就做完了?? 喵喵喵? // luogu-judger-enable-o2 #include<bits/stdc++.h> # ...
- 【线性基合并 树链剖分】bzoj4568: [Scoi2016]幸运数字
板子题 Description A 国共有 n 座城市,这些城市由 n-1 条道路相连,使得任意两座城市可以互达,且路径唯一.每座城市都有一个 幸运数字,以纪念碑的形式矗立在这座城市的正中心,作为城市 ...
- bzoj4568 [Scoi2016]幸运数字 线性基+树链剖分
A 国共有 n 座城市,这些城市由 n-1 条道路相连,使得任意两座城市可以互达,且路径唯一.每座城市都有一个 幸运数字,以纪念碑的形式矗立在这座城市的正中心,作为城市的象征.一些旅行者希望游览 A ...
随机推荐
- Python网络编程(epoll内核监听,多任务多进程)
OJBK 接着昨天的说 select模块内的epoll函数还没说 说完epoll和本地套接字套接字基本就没了 今天主要是多进程 理论性东西比较多 主要是理解 epoll ...
- 孤荷凌寒自学python第四十六天开始建构自己用起来更顺手一点的Python模块与类尝试第一天
孤荷凌寒自学python第四十六天开始建构自己用起来更顺手一点的Python模块与类,尝试第一天 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 按上一天的规划,这是根据过去我自学其它编程语 ...
- Elasticsearch查询优化总结
查询优化 1 从提高查询精确度进行优化: 本部分主要针对全文搜索进行探究. 1.1 倒排索引 1.1.1 什么是倒排索引: 一个倒排索引由文档中所有不重复词的列表构成,对于其中每个词,有一个包含它的文 ...
- Java 循环队列的实现
队列概念 队列(Queue)是限定只能在一端插入.另一端删除的线性表.允许删除的一端叫做队头(front),允许插入的一端叫做队尾(rear),没有元素的队列称为“空队列”. 队列具有先进先出(FIF ...
- ASP.NET Core MVC 运行所选代码生成器时出错
添加Nuget Microsoft.VisualStudio.Web.CodeGeneration.Design Microsoft.EntityFrameworkCore.Tools
- vmware中linux虚拟机使用NAT模式不能连接外网解决
linux虚拟机一直配置的桥接模式,今天改成NAT模式发现不能上外网 环境:VMware12,CentOS 6.8,NAT模式 ①电脑实际ip:192.168.1.100 ②NAT使用虚拟网卡网关: ...
- POJ 1204 Word Puzzles | AC 自动鸡
题目: 给一个字母矩阵和几个模式串,矩阵中的字符串可以有8个方向 输出每个模式串开头在矩阵中出现的坐标和这个串的方向 题解: 我们可以把模式串搞成AC自动机,然后枚举矩阵最外围一层的每个字母,向八个方 ...
- HDU 4910 HDOJ Problem about GCD BestCoder #3 第四题
首先 m = 1 时 ans = 0对于 m > 1 的 情况 由于 1 到 m-1 中所有和m互质的数字,在 对m的乘法取模 运算上形成了群 ai = ( 1<=a<m & ...
- Uva10635 Prince and Princess
题目戳这里 这题如果用\(f_{i,j}\)这样dp的话肯定过不了,必须另辟蹊径.题目说了数字不重复.我们先只留下两个数组共有的数字.然后我们处理出这样一个数组\(S\),\(S_i\)表示\(A_i ...
- YV12 NV12区别
用videoCapture和IAMStreamConfig拿到的支持的格式列表.发现支持2中图像格式,YV12和NV12.具体是怎么样的内存分布不知道.查了些文档.自己修改了几个图.看出了点端倪 YV ...