【线性基合并 树链剖分】bzoj4568: [Scoi2016]幸运数字
板子题
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
第一行包含 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
输出需要包含 q 行,每行包含 1 个非负整数,表示这名旅行者可以保留的最大幸运值。
题目分析
树剖/倍增的板子题
想用树剖来做一做,然而TLE了好几发。
发现自己常数意识太差,每次query时候都开一个线性基,活生生浪费10s+
1 #include<bits/stdc++.h> 2 #define ENS //__attribute__((optimize("-O2"))) 3 #define NES //__attribute__((optimize("-O2"))) //__inline__ __attribute__((always_inline)) 4 typedef long long ll; 5 const int maxn = 20035; 6 const int maxm = 40035; 7 const int maxq = 200035; 8 9 struct Linear 10 { 11 ll p[103]; 12 Linear(){memset(p, 0, sizeof p);} 13 NES void insert(ll c) 14 { 15 for (int i=60, chk=0; i>=0&&!chk; i--) 16 if (c>>i){ 17 if (p[i]) c ^= p[i]; 18 else p[i] = c, chk = 1; 19 } 20 } 21 NES void merge(Linear b) 22 { 23 for (int i=60; i>=0; i--) 24 if (b.p[i]) insert(b.p[i]); 25 } 26 NES ll max() 27 { 28 ll ret = 0; 29 for (int i=60; i>=0; i--) 30 if ((ret^p[i]) > ret) ret ^= p[i]; 31 return ret; 32 } 33 }f[maxn<<2]; 34 struct node 35 { 36 int fa,son,top,tot; 37 }a[maxn]; 38 int n,q,chain[maxn],chTot,dep[maxn]; 39 int edgeTot,head[maxn],nxt[maxm],edges[maxm]; 40 ll g[maxn],cnVal[maxn]; 41 42 template <typename T> NES void read(T&x) 43 { 44 char cu=getchar();x=0;bool fla=0; 45 while(!isdigit(cu)){if(cu=='-')fla=1;cu=getchar();} 46 while(isdigit(cu))x=x*10+cu-'0',cu=getchar(); 47 if(fla)x=-x; 48 } 49 void write(ll x){if (x/10) write(x/10);putchar('0'+x%10);} 50 void writeln(ll x){write(x), putchar('\n');} 51 NES void addedge() 52 { 53 int u,v; 54 read(u), read(v); 55 edges[++edgeTot] = v, nxt[edgeTot] = head[u], head[u] = edgeTot; 56 edges[++edgeTot] = u, nxt[edgeTot] = head[v], head[v] = edgeTot; 57 } 58 void dfs1(int x, int fa) 59 { 60 a[x].son = a[x].top = -1, a[x].fa = fa; 61 a[x].tot = 1, dep[x] = dep[fa]+1; 62 for (int i=head[x]; i!=-1; i=nxt[i]) 63 { 64 int v = edges[i]; 65 if (v!=fa){ 66 dfs1(v, x), a[x].tot += a[v].tot; 67 if (a[x].son==-1||a[a[x].son].tot < a[v].tot) a[x].son = v; 68 } 69 } 70 } 71 void dfs2(int x, int top) 72 { 73 a[x].top = top, chain[x] = ++chTot, cnVal[chTot] = g[x]; 74 if (a[x].son==-1) return; 75 dfs2(a[x].son, top); 76 for (int i=head[x]; i!=-1; i=nxt[i]) 77 { 78 int v = edges[i]; 79 if (v!=a[x].son&&v!=a[x].fa) dfs2(v, v); 80 } 81 } 82 void build(int rt, int l, int r) 83 { 84 if (l==r){ 85 f[rt].insert(cnVal[l]); 86 return; 87 } 88 int mid = (l+r)>>1; 89 build(rt<<1, l, mid); 90 build(rt<<1|1, mid+1, r); 91 f[rt] = f[rt<<1], f[rt].merge(f[rt<<1|1]); 92 } 93 Linear query(int rt, int l, int r, int L, int R) 94 { 95 if (L <= l&&r <= R) return f[rt]; 96 int mid = (l+r)>>1; 97 if (L <= mid&&R > mid){ 98 99 Linear tmp = query(rt<<1, l, mid, L, R); 100 tmp.merge(query(rt<<1|1, mid+1, r, L, R)); 101 return tmp; 102 }else if (L <= mid) return query(rt<<1, l, mid, L, R); 103 else if (R > mid) return query(rt<<1|1, mid+1, r, L, R); 104 } 105 NES void queryChain() 106 { 107 Linear ret; 108 int x,y; 109 read(x), read(y); 110 while (a[x].top!=a[y].top) 111 { 112 if (dep[a[x].top] > dep[a[y].top]) std::swap(x, y); 113 ret.merge(query(1, 1, n, chain[a[y].top], chain[y])); 114 y = a[a[y].top].fa; 115 } 116 if (dep[x] > dep[y]) std::swap(x, y); 117 ret.merge(query(1, 1, n, chain[x], chain[y])); 118 writeln(ret.max()); 119 } 120 ENS int main() 121 { 122 memset(head, -1, sizeof head); 123 read(n), read(q); 124 for (int i=1; i<=n; i++) read(g[i]); 125 for (int i=1; i<n; i++) addedge(); 126 dfs1(1, 0), dfs2(1, 1); 127 build(1, 1, n); 128 while (q--) queryChain(); 129 return 0; 130 }
END