bzoj4568 Scoi2016 幸運數字

2022-05-02 05:36:08 字數 3238 閱讀 5319

a 國共有 n 座城市,這些城市由 n-1 條道路相連,使得任意兩座城市可以互達,且路徑唯一。每座城市都有乙個幸運數字,以紀念碑的形式矗立在這座城市的正中心,作為城市的象徵。一些旅行者希望遊覽 a 國。旅行者計畫乘飛機降落在 x 號城市,沿著 x 號城市到 y 號城市之間那條唯一的路徑遊覽,最終從 y 城市起飛離開 a 國。在經過每一座城市時,遊覽者就會有機會與這座城市的幸運數字拍照,從而將這份幸運儲存到自己身上。然而,幸運是不能簡單疊加的,這一點遊覽者也十分清楚。他們迷信著幸運數字是以異或的方式保留在自己身上的。例如,遊覽者拍了 3 張**,幸運值分別是 5,7,11,那麼最終保留在自己身上的幸運值就是 9(5 xor 7 xor 11)。有些聰明的遊覽者發現,只要選擇性地進行拍照,便能獲得更大的幸運值。例如在上述三個幸運值中,只選擇 5 和 11 ,可以保留的幸運值為 14 。現在,一些遊覽者找到了聰明的你,希望你幫他們計算出在他們的行程安排中可以保留的最大幸運值是多少。

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

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

4 2

11 5 7 9

1 2

1 3

1 4

2 3

1 414

11正解:樹鏈剖分+線段樹套線性基。

這題好勁啊。。$o(nlog^n)$的演算法還是很剛的。

這題我們是要求樹上路徑異或最大值,且這個異或是任意選數異或的,所以我們可以自然地想到線性基。然後我們必須要區間線性基,所以我們在外面套乙個線段樹。然後這題是在樹上的操作,所以寫樹鏈剖分。然後這題就做完了。。

這題似乎還有個更優秀的點分治做法,複雜度只要$o(nlog^n)$,似乎很優秀啊。。先填個坑吧。。

1

//it is made by wfj_2048~

2 #include 3 #include 4 #include 5 #include 6 #include 7 #include 8 #include 9 #include 10 #include 11 #include 12 #include 13 #include

14#define inf (1<<30)

15#define n (20010)

16#define ls (x<<1)

17#define rs (x<<1|1)

18#define il inline

19#define rg register

20#define ll long long

21#define file(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)

2223

using

namespace

std;

2425

struct edgeg[2*n];

26struct

nodeq[n];

2728

ll head[n],top[n],fa[n],son[n],dep[n],sz[n],tid[n],pos[n],n,q,num,cnt;

29 ll sum[4*n][62],ss[62],xx[62

],a[n];

3031

il ll gi()

3839

il ll gll()

4647 il void insert(rg ll from,rg ll to),head[from]=num;return

; }48

49 il void

dfs1(rg ll x,rg ll p)

56return;57

}5859 il void

dfs2(rg ll x,rg ll p,rg ll anc)

66return;67

}6869 il void ins(ll *p,rg ll x)

73 x^=p[i];74}

75return;76

}7778 il void merge(ll *a,ll *b)

8384 il ll getmax(ll *p)

9091 il void

build(rg ll x,rg ll l,rg ll r)

93 rg ll mid=(l+r)>>1; build(ls,l,mid),build(rs,mid+1

,r);

94 merge(sum[x],sum[ls]),merge(sum[x],sum[rs]); return;95

}9697 il void

query(rg ll x,rg ll l,rg ll r,rg ll xl,rg ll xr)

99 rg ll mid=(l+r)>>1

;100

if (xr<=mid) query(ls,l,mid,xl,xr);

101else

if (xl>mid) query(rs,mid+1

,r,xl,xr);

102else query(ls,l,mid,xl,mid),query(rs,mid+1,r,mid+1

,xr);

103return

;104

}105

106il ll query(rg ll u,rg ll v)

113if (dep[u]>dep[v]) swap(u,v);

114 q[++ccnt].l=tid[u],q[ccnt].r=tid[v];

115 memset(ss,0,sizeof

(ss));

116for (rg ll i=1;i<=ccnt;++i)

121return

getmax(ss);

122}

123124 il void

work()

131 dfs1(1,0),dfs2(1,0,1); build(1,1

,n);

132for (rg ll i=1;i<=q;++i)

136return

;137

}138

139int

main()

BZOJ4568 Scoi2016 幸運數字

樹上查兩點間最大異或和 樹倍增,每個點維護向上2 k個點的線性基,然後在查lca的時候合併 關於點權維護倍增略蛋疼 合併線性基的時候就直接把乙個線性基里的插到另乙個裡 複雜度o m log n log 2inf 合併的時候加點優化可以降掉乙個loginf 接下來bb一些有關線性基和最大異或和的東西 ...

BZOJ 4568 Scoi2016 幸運數字

題目大意 給你一顆樹,多個詢問,問你樹上任意兩點的路徑上選任意幾個點使得異或和最大。我是參考的claris大神的 點分治,對於詢問在兩個子樹間或者有乙個在重心上的進行回答,否則把問題用鍊錶接到詢問點所在的子樹上。具體方法可以選中重心都對每個子樹染色,染為這個子樹的根節點。在子樹處理問題之前一定要記住...

BZOJ 4568 Scoi2016 幸運數字

可以合併的東西都是人類互相傷害的 參照cogs上採礦那道題 可以用樹剖維護線性基,複雜度q logn 2 logw 2 顯然會t。考慮到沒有修改 用點分治離線來做 乙個詢問如果經過當前分治根,則立即處理並不再下傳,否則下傳到相應子樹去做 複雜度nlognlogw qlogwlogw include ...