BZOJ 4568 Scoi2016 幸運數字

2021-07-11 22:22:51 字數 1505 閱讀 9801

題目大意:給你一顆樹,多個詢問,問你樹上任意兩點的路徑上選任意幾個點使得異或和最大。

我是參考的claris大神的**(%%%),點分治,對於詢問在兩個子樹間或者有乙個在重心上的進行回答,否則把問題用鍊錶接到詢問點所在的子樹上。

具體方法可以選中重心都對每個子樹染色,染為這個子樹的根節點。在子樹處理問題之前一定要記住先把詢問拖出來,然後把子樹的問題清零。因為你選的是這個子樹的重心開始分治,而不是根,所以這個子樹的根可能就會又加入一些問題,你不清零就會重複計算一些問題和出錯。

然後是對於重心到子樹每個點都求一次線性基,最後暴力合併在不同子樹兩點的線性基就是答案(claris的線性基也是%%%%),具體可參照**

#include

#include

using namespace std;

typedef long long ll;

const int n = 20010, m = 40010, q = 200010

*30, e = 200010;

int n, m, g[n], to[m], nxt[m], ok[m], np, g[n], to[q], nxt[q], np, now, all, son[n], color[n], f[n];

ll w[n], ans[e];

struct dataq[e];

struct gauss

inline void ins(ll x) } }

inline ll ask()

}h[n], tmp;

templateinline void read(t &x)

char buf[30];

templateinline void out(t x)

while(i) putchar(buf[i--]);

putchar('\n');

}inline void push(int

x,int

y) inline void push(int

x,int

y) void findg(int

x, int fa)

f[x] = f[x] < (all-son[x]) ? (all-son[x]) : f[x];

if(f[now] > f[x]) now = x;

}void paint(int

x,int fa,int c)

}void work(int

x) else push(color[q[i].x],i);

} for(int i=g[now];i;i=nxt[i]) if(ok[i])

}int main()

for(int i=1;i<=m;i++) read(q[i].x), read(q[i].y);

for(int i=1;i<=m;i++)

work(1);

for(int i=1;i<=m;i++) out(ans[i]);

return

0; }

BZOJ4568 Scoi2016 幸運數字

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

BZOJ 4568 Scoi2016 幸運數字

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

BZOJ4568 Scoi2016 幸運數字

線性基 倍增 lca 抑或和最大的問題顯然要用到線性基。本題就直接倍增維護線性基,合併出答案即可。線性基的合併就是乙個插入到另乙個中。有一點小細節就是lb i j 中維護的是從i到i的2j 級祖先的線性基,左開右閉,也就是不包括i本身的。因此查lc a a,b 的時候先把a和b的插入進去。code ...