題目傳送門
題目大意:有一棵樹,點帶權,每次問如何從 x
xx 到 y
yy 路徑上的點中選擇一些點使得他們的權值的異或和最大,輸出這個最大的異或和。
從一些值中選擇一些值,使得他們的異或和最大,顯然就是線性基呀!
那要求一條路徑的線性基,用 lca
lcalc
a 即可,開個結構體 f
ff,f[i
][j]
.x
f[i][j].x
f[i][j
].x 表示 i
ii 點往上跳 2
j2^j
2j個點所能到達的祖先,f[i
][j]
.d
f[i][j].d
f[i][j
].d 表示 i
ii 點到 f[i
][j]
.x
f[i][j].x
f[i][j
].x 的路徑上的所有點的權值的線性基 (注意 d
dd 是陣列)。
求的時候,將 x
xx 到 lca
(x,y
)lca(x,y)
lca(x,
y)的線性基與 y
yy 到 lca
(x,y
)lca(x,y)
lca(x,
y)的線性基暴力合併1
即可,求 lca
lcalc
a 的倍增陣列時,線性基也是暴力合併。
如果還有不明白的,就看**吧:
#include
#include
#define ll long long
int n,m,len=0;
struct nod
void
add(ll x)
//插入
else x^
=d[i];}
}}ll ans()
//最大值求解
}f[20010][
20];//倍增陣列
struct node
;node e[
40010];
ll a[
20010];
int first[
40010];
void
buildroad
(int x,
int y)
int deep[
20010];
void
dfs_getfa
(int x)
//處理倍增陣列初值
}void
swap
(int
&x,int
&y)void
work
(int x,
int y)}}
for(
int j=
14;j>=
0;j--)if
(f[x]
[j].x!=f[y]
[j].x)
x=f[x]
[j].x;y=f[y]
[j].x;}if
(x!=y)
}printf
("%lld\n"
,ans.
ans())
;}intmain()
deep[1]
=1;dfs_getfa(1
);for(
int j=
1;j<=
14;j++
)for
(int i=
1;i<=n;i++
)//求倍增陣列
for(
int i=
1;i<=m;i++
)}
什麼?你說不會暴力合併?直接將乙個線性基中的元素暴力插入到另乙個就可以了呀! ↩︎ SCOI2016 幸運數字 題解
題目大意見原題面。其實這個題的思路非常簡單,我們知道一些數字的最大異或和可以用線性基來在o l ogva lmax o log val o lo alma x 時間內快速求取,而線性基的合併也才o l og2v alma x o log 2 val o log2 valm ax 所以我們可以用個資料...
SCOI2016 幸運數字
線性基合併o log 2n 不能更小 但是倍增o qlog 3n 可過233333 甚至樹剖o qlog 4n 可過666666 還有乙個樹上路徑查詢利器 點分治!詢問離線 列舉重心,處理路徑過重心的詢問 邊dfs邊插入線性基,維護每個點到根路徑上的線性基 每個詢問,如果所屬不同的子樹,那麼過當前重...
SCOI2016 幸運數字
不想說了.就樹上的線性基合併.但是講道理o nlogn 3 為什麼能過去呢.但是就是能過去啊,因為博主是菜雞不怎麼會澱粉質啊,所以本篇題解只能提供這個複雜度的演算法了qaq 求選出來一些數使得異或和最大?線性基啊!那怎麼求路徑上的呢?乙個乙個往上合併,一直合併到lca就行了吧!乙個乙個合併顯然不行,...