SCOI 2016 幸運數字 題解

2021-08-30 19:37:30 字數 1920 閱讀 6030

題目傳送門

題目大意:有一棵樹,點帶權,每次問如何從 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就行了吧!乙個乙個合併顯然不行,...