SCOI2016 幸運數字 題解

2021-09-10 19:21:26 字數 1864 閱讀 8263

題目大意見原題面。

其實這個題的思路非常簡單,我們知道一些數字的最大異或和可以用線性基來在o(l

ogva

lmax

)o(log\ val_)

o(lo**

alma

x​)時間內快速求取,而線性基的合併也才o(l

og2v

alma

x)

o(log^2\ val_)

o(log2

valm

ax​)

,所以我們可以用個資料結構維護線性基,然後每次查詢就將那條鏈上的線性基拿出來求取答案即可。

用線段樹+樹鏈剖分來,雖然支援修改,但這個方法不好寫,而且複雜度還多乙個log

nlogn

logn

。由於沒有修改所以直接預處理倍增陣列和倍增的線性基,然後每次跳一遍合併出線性基即可。

第二種方法只有o((

n+q)

logn

(602

))

o((n+q)logn(60^2))

o((n+q

)log

n(60

2)),而第一種則是o(n

+q)l

og2n

(602

))

o(n+q)log^2n(60^2))

o(n+q)

log2

n(60

2)),所以直接寫倍增吧,**如下:

#include

#include

#include

#define ll long long

using

namespace std;

const

int m=

2e4+10;

int n,m;

int jump[m][17

],dep[m]

;ll f[m][17

][62]

,lb[62]

;ll val[m]

;struct ss

}g[m<<1]

;int head[m]

,cnt;

void

add(

int a,

int b)

void

insert

(ll *a,ll x)

else x^

=a[i];}

//線性基插入

}void

merge

(ll *a,ll *b)

//線性基合併

void

dfs(

int a,

int fa)

for(

int i=head[a]

;i;i=g[i]

.last)

}//倍增

intlca

(int a,

int b)

if(a==b)

return a;

for(

int i=

16;i>=

0;i--)}

merge

(lb,f[a][0

]);insert

(lb,val[b]);

return jump[a][0

];}ll a;

int b,c;

void

file()

void

close()

intmain()

for(

int i=

1;i)dfs(1

,0);

while

(m--

)close()

;return0;

}

SCOI 2016 幸運數字 題解

題目傳送門 題目大意 有一棵樹,點帶權,每次問如何從 x xx 到 y yy 路徑上的點中選擇一些點使得他們的權值的異或和最大,輸出這個最大的異或和。從一些值中選擇一些值,使得他們的異或和最大,顯然就是線性基呀!那要求一條路徑的線性基,用 lca lcalc a 即可,開個結構體 f ff,f i ...

SCOI2016 幸運數字

線性基合併o log 2n 不能更小 但是倍增o qlog 3n 可過233333 甚至樹剖o qlog 4n 可過666666 還有乙個樹上路徑查詢利器 點分治!詢問離線 列舉重心,處理路徑過重心的詢問 邊dfs邊插入線性基,維護每個點到根路徑上的線性基 每個詢問,如果所屬不同的子樹,那麼過當前重...

SCOI2016 幸運數字

不想說了.就樹上的線性基合併.但是講道理o nlogn 3 為什麼能過去呢.但是就是能過去啊,因為博主是菜雞不怎麼會澱粉質啊,所以本篇題解只能提供這個複雜度的演算法了qaq 求選出來一些數使得異或和最大?線性基啊!那怎麼求路徑上的呢?乙個乙個往上合併,一直合併到lca就行了吧!乙個乙個合併顯然不行,...