SCOI2016 幸運數字 點分治 線性基

2021-09-29 02:12:39 字數 3351 閱讀 1731

《更新提示》

《正文》

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 format

第一行包含 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 format

輸出需要包含 q 行,每行包含 1 個非負整數,表示這名旅行者可以保留的最大幸運值。

sample input

4211

5791

2131

4231

4

sample output
14

11

solution

元素的異或最大值考慮使用線性基來求解,那麼問題就是如何處理樹上路徑,轉為序列問題。

最粗暴的想法是樹鏈剖分,然後用線段樹維護樹上路徑的線性基,向上合併即可。查詢也是樹鏈剖分的方法,時間複雜度o(n

log⁡3n

+q

log⁡4n

)o(n\log^3n+q\log^4n)

o(nlog3n

+qlog4n)

,因為線性基的合併是o(l

og2n

)o(log^2n)

o(log2

n)的。考慮到沒有修改操作,使用線段樹比較浪費,可以直接樹上倍增,時間複雜度優化為o((

n+q)

log⁡3n

)o((n+q)\log^3n)

o((n+q

)log3n

)。更好的做法是點分治。我們知道點分治可以統計樹上路徑問題,那麼點分治同樣也可以回答樹上路徑詢問。具體的說,我們每次回答經過分治重心的路徑所對應的詢問,只需在dfs

dfsdf

s這棵樹的同時求出重心到每乙個點路徑上的線性基,那麼對於每乙個詢問,只要合併兩個線性基即可,時間複雜度優化為o((

n+q)

log⁡2n

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

o((n+q

)log2n

)。

#include

using

namespace std;

typedef

long

long ll;

typedef pair<

int,

int> pii;

const

int n =

20020

, m =

200020

;struct linearbase

inline

void

insert

(ll x)

inline ll query

(void)}

;typedef linearbase lbase;

struct edge e[n*2]

;int n,m,t,head[n]

,rec[n]

; ll a[n]

,ans[m]

;int size[n]

,max[n]

,flag[n]

,root,tot;

vector q[n]

; lbase b[n]

;inline

intread

(void

)inline ll readll

(void

)inline

void

insert

(int x,

int y)

, head[x]

= t;

}inline lbase merge

(lbase p,lbase q)

return res;

}inline

void

input

(void

)for

(int i=

1;i<=m;i++

) q[u]

.push_back

(make_pair

(v,i));

q[v]

.push_back

(make_pair

(u,i));

}}inline

voiddp(

int x,

int fa)

max[x]

=max

( max[x]

, tot - size[x]);

if( max[x]

< max[root]

) root = x;

}inline

void

dfs1

(int x,

int fa,

int rt)

for(

int i=head[x]

;i;i=e[i]

.next)

}inline

void

dfs2

(int x,

int fa,

int v)

}inline

void

divide

(int x)

dfs2

( x ,0,

0);for

(int i=head[x]

;i;i=e[i]

.next)

}int

main

(void

)

《後記》

SCOI2016 幸運數字

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

SCOI2016 幸運數字

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

SCOI2016 幸運數字

題目 來寫乙個 3 個 log 的垃圾做法 其實非常顯然就是倍增把這條路徑處理一遍,之後維護出倍增陣列的線性基,大力合併就好了 線性基合併就是把乙個線性基的所有元素都拿出來,乙個乙個插入到另外乙個中去 include include include include define maxn 20005...