[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^60

Output

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

Sample Input

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

Sample Output

14
11

HINT

Source

[Submit][Status][Discuss]

线性基不支持删除,但是支持插入与合并,于是显然可以树剖维护,$O(n\log^4n)$。

线性基不支持修改,浪费了线段树支持修改的功能,实际上可以直接用不支持修改的ST表,$O(n\log^3n)$。

点分治不仅可以做路径统计问题,还可以处理与路径有关的询问问题,将每个询问的两个点的vector中放入这个询问,每次递归到一个重心时查找管辖范围内的所有询问,因为一个询问只涉及两个点,所以复杂度是有保证的。$O(n\log^2n)$

下面是倍增LCA的代码,要注意关于点的LCA和普通的是有区别的:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define rep(i,l,r) for (int i=l; i<=r; i++)
 5 typedef long long ll;
 6 using namespace std;
 7
 8 const int N=20100,M=62;
 9 ll g[N][16][M],Ans[M],a[N];
10 int n,Q,u,v,cnt,to[N<<1],nxt[N<<1],h[N],d[N],fa[N][16];
11
12 void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; }
13 void ins(ll p[],ll x){
14     for (int i=61; ~i; i--) if (x&(1ll<<i)){
15         if (!p[i]) { p[i]=x; break; } else x^=p[i];
16     }
17 }
18 void merge(ll g[],ll f1[],ll f2[]){
19     rep(i,0,61) g[i]=f1[i];
20     rep(i,0,61) if (f2[i]) ins(g,f2[i]);
21 }
22 void dfs(int x){
23     ins(g[x][0],a[x]);
24     rep(i,1,15){
25         fa[x][i]=fa[fa[x][i-1]][i-1];
26         merge(g[x][i],g[x][i-1],g[fa[x][i-1]][i-1]);
27     }
28     for (int i=h[x],k; i; i=nxt[i])
29         if ((k=to[i])!=fa[x][0]) fa[k][0]=x,d[k]=d[x]+1,dfs(k);
30 }
31
32 void lca(int u,int v){
33     memset(Ans,0,sizeof(Ans));
34     if (d[u]<d[v]) swap(u,v);
35     int t=d[u]-d[v];
36     for (int i=15; ~i; i--)
37         if (t&(1<<i)) merge(Ans,Ans,g[u][i]),u=fa[u][i];
38     if (u==v){ merge(Ans,Ans,g[u][0]); return; }
39     for (int i=15; ~i; i--)
40         if (fa[u][i]!=fa[v][i])
41             merge(Ans,Ans,g[u][i]),merge(Ans,Ans,g[v][i]),
42             u=fa[u][i],v=fa[v][i];
43     merge(Ans,Ans,g[u][0]); merge(Ans,Ans,g[v][0]);
44     merge(Ans,Ans,g[fa[u][0]][0]);
45 }
46
47 ll get(ll p[]){
48     ll res=0;
49     for (int i=61; ~i; i--) res=max(res,res^p[i]);
50     return res;
51 }
52
53 int main(){
54      freopen("bzoj4568.in","r",stdin);
55      freopen("bzoj45682.out","w",stdout);
56     scanf("%d%d",&n,&Q);
57     rep(i,1,n) scanf("%lld",&a[i]);
58     rep(i,2,n) scanf("%d%d",&u,&v),add(u,v),add(v,u);
59     dfs(1);
60     while (Q--) scanf("%d%d",&u,&v),lca(u,v),printf("%lld\n",get(Ans));
61     return 0;
62 }

然后是点分治,本机时间跑的是倍增的一半,交到OJ上就莫名其妙的死活TLE,弃疗。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<vector>
 4 #include<algorithm>
 5 #define rep(i,l,r) for (int i=l; i<=r; i++)
 6 #define For(i,x) for (int i=h[x],k; i; i=nxt[i])
 7 typedef long long ll;
 8 using namespace std;
 9
10 const int N=20010,M=200010,inf=1000000000;
11 int n,Q,u,v,cnt,S,rt,tim,pos[N],f[N],b[N],sz[N],vis[N],d[N];
12 int fa[N][16],h[N],to[N<<1],nxt[N<<1];
13 ll a[N],g[N][65],Ans[65],ans[M];
14 struct P{ int u,v; }s[M];
15 vector<int>V[N];
16 void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; }
17
18 void ins(ll p[],ll x){
19     for (int i=60; ~i; i--) if (x&(1ll<<i)){
20         if (!p[i]) { p[i]=x; break; } else x^=p[i];
21     }
22 }
23
24 void merge(ll g[],ll f1[],ll f2[]){
25     rep(i,0,60) g[i]=f1[i];
26     rep(i,0,60) if (f2[i]) ins(g,f2[i]);
27 }
28
29 ll get(ll p[]){
30     ll res=0;
31     for (int i=60; ~i; i--) res=max(res,res^p[i]);
32     return res;
33 }
34
35 void find(int x,int fa){
36     f[x]=0; sz[x]=1;
37     For(i,x) if ((k=to[i])!=fa && !vis[k])
38         find(k,x),sz[x]+=sz[k],f[x]=max(f[x],sz[k]);
39     f[x]=max(f[x],S-sz[x]);
40     if (f[x]<f[rt]) rt=x;
41 }
42
43 void work(int x,int fa,int bel){
44     pos[x]=bel; b[x]=tim;
45     rep(i,0,60) g[x][i]=g[fa][i]; ins(g[x],a[x]);
46     For(i,x) if ((k=to[i])!=fa && !vis[k]) work(k,x,bel);
47 }
48
49 void work1(int x,int fa){
50     for (vector<int>::iterator it=V[x].begin(); it!=V[x].end(); it++){
51         int k=*it; if (ans[k]) continue;
52         int u=s[k].u; if (u==x) u=s[k].v;
53         if (b[u]==tim && (pos[u]!=pos[x] || !pos[u]))
54             merge(Ans,g[u],g[x]),ans[k]=get(Ans);
55     }
56     For(i,x) if ((k=to[i])!=fa && !vis[k]) work1(k,x);
57 }
58
59 void solve(int x){
60     vis[x]=1; b[x]=++tim; pos[x]=0;
61     rep(i,0,60) g[x][i]=0; ins(g[x],a[x]);
62     For(i,x) if (!vis[k=to[i]]) work(k,x,k); work1(x,0);
63     For(i,x) if (!vis[k=to[i]]) S=sz[k],f[rt=0]=inf,find(k,x),solve(k);
64 }
65
66 int main(){
67     freopen("bzoj4568.in","r",stdin);
68     freopen("bzoj4568.out","w",stdout);
69     scanf("%d%d",&n,&Q);
70     rep(i,1,n) scanf("%lld",&a[i]);
71     rep(i,2,n) scanf("%d%d",&u,&v),add(u,v),add(v,u);
72     rep(i,1,Q) scanf("%d%d",&s[i].u,&s[i].v),V[s[i].u].push_back(i),V[s[i].v].push_back(i);
73     f[rt=0]=inf; S=n; find(1,0); solve(rt);
74     rep(i,1,Q) printf("%lld\n",ans[i]);
75     return 0;
76 }

原文地址:https://www.cnblogs.com/HocRiser/p/8979005.html

时间: 2024-10-03 22:38:49

[BZOJ4568][SCOI2016]幸运数字(倍增LCA,点分治+线性基)的相关文章

bzoj4568 [Scoi2016]幸运数字

Description A 国共有 n 座城市,这些城市由 n-1 条道路相连,使得任意两座城市可以互达,且路径唯一.每座城市都有一个幸运数字,以纪念碑的形式矗立在这座城市的正中心,作为城市的象征.一些旅行者希望游览 A 国.旅行者计划乘飞机降落在 x 号城市,沿着 x 号城市到 y 号城市之间那条唯一的路径游览,最终从 y 城市起飞离开 A 国.在经过每一座城市时,游览者就会有机会与这座城市的幸运数字拍照,从而将这份幸运保存到自己身上.然而,幸运是不能简单叠加的,这一点游览者也十分清楚.他们迷

bzoj4568: [Scoi2016]幸运数字 线性基 倍增

洛谷T了,mmp 还是bzoj时限良心,虽然三天两头爆炸 算是简单的题吧,构造出每个点logn个的线性基表 感觉线性基最nb的就是只有log个,所以可以做的很暴力 合并就是拆开再并 1 #include <bits/stdc++.h> 2 using namespace std; 3 struct Bas 4 { 5 long long a[61]; 6 Bas() 7 { 8 for(int i=0;i<=60;i++) 9 a[i]=0; 10 } 11 void add(long

【BZOJ-4568】幸运数字 树链剖分 + 线性基合并

4568: [Scoi2016]幸运数字 Time Limit: 60 Sec  Memory Limit: 256 MBSubmit: 238  Solved: 113[Submit][Status][Discuss] Description A 国共有 n 座城市,这些城市由 n-1 条道路相连,使得任意两座城市可以互达,且路径唯一.每座城市都有一个幸运数字,以纪念碑的形式矗立在这座城市的正中心,作为城市的象征.一些旅行者希望游览 A 国.旅行者计划乘飞机降落在 x 号城市,沿着 x 号城市

bzoj 4568: [Scoi2016]幸运数字

4568: [Scoi2016]幸运数字 Time Limit: 60 Sec  Memory Limit: 256 MBSubmit: 848  Solved: 336[Submit][Status][Discuss] Description A 国共有 n 座城市,这些城市由 n-1 条道路相连,使得任意两座城市可以互达,且路径唯一.每座城市都有一个 幸运数字,以纪念碑的形式矗立在这座城市的正中心,作为城市的象征.一些旅行者希望游览 A 国.旅行者计划 乘飞机降落在 x 号城市,沿着 x 号

【BZOJ 4568】 4568: [Scoi2016]幸运数字 (线性基+树链剖分+线段树)

4568: [Scoi2016]幸运数字 Description A 国共有 n 座城市,这些城市由 n-1 条道路相连,使得任意两座城市可以互达,且路径唯一.每座城市都有一个 幸运数字,以纪念碑的形式矗立在这座城市的正中心,作为城市的象征.一些旅行者希望游览 A 国.旅行者计划 乘飞机降落在 x 号城市,沿着 x 号城市到 y 号城市之间那条唯一的路径游览,最终从 y 城市起飞离开 A 国. 在经过每一座城市时,游览者就会有机会与这座城市的幸运数字拍照,从而将这份幸运保存到自己身上.然而,幸

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

https://www.lydsy.com/JudgeOnline/problem.php?id=4568 https://www.luogu.org/problemnew/show/P3292 A 国共有 n 座城市,这些城市由 n-1 条道路相连,使得任意两座城市可以互达,且路径唯一.每座城市都有一个幸运数字,以纪念碑的形式矗立在这座城市的正中心,作为城市的象征. 一些旅行者希望游览 A 国.旅行者计划乘飞机降落在 x 号城市,沿着 x 号城市到 y 号城市之间那条唯一的路径游览,最终从 y

luoguP3292 [SCOI2016]幸运数字(线性基+树上倍增)

传送:https://www.luogu.org/problem/P3292 题意: $n$座城市,$n-1$条路,每个城市有一个价值$a_i$.$q$个询问,每次询问城市$x$到城市$y$的路径上经过的城市的价值的最大异或和为多少. 数据范围: $1<=n<=20000,q<=200000,a_i<=2^{60}$. 分析: 对于一次询问$x-->y$的路径上的答案,很明显就是$x-->lca(x,y)$的线性基并上$y-->lca(x,y)$的线性基,然后求最

SCOI2016 幸运数字

传送门 如果只是一条路径的话,那就是非常简单的线性基. 不过要考虑多组询问-- 考虑到n比较小,我们可以模仿倍增LCA的方法,预处理倍增的线性基.在每次路径上跳的时候把线性基合并最后求解即可.具体的做法是,我们用\(p[i][x][j]\)表示在编号为x的点处,向上跳\(2^i\)步以内,线性基第j位的数.这个可以合并,比较好写的方法就是直接传两个数组进去合并. 之后就正常了.代码很短,不到100行.(我交了好多次因为忘记用longlong快读了--) #include<iostream> #

[SCOI2016]幸运数字 线性基

题面 题面 题解 题面意思非常明确:求树上一条链的最大异或和. 我们用倍增的思想. 将这条链分成2部分:x ---> lca , lca ---> y 分别求出这2个部分的线性基,然后合并,再求最大异或和. 所以我们现在只需要考虑如何在树上求一条无需拐弯的链的最大线性基. 考虑倍增. 我们预处理出f[i][j]表示从点i开始向上走\(2^j\)构成的链的线性基.至于只有点\(i\)一个点的线性基,我们可以在运算的时候特判一下处理. 暴力预处理后,我们就可以最多 合并3次 + 求LCA的复杂度