A: A Math Problemnode
題意:給出一個n,找出有多少個k知足kk <= nios
思路: kk的增加很快,當k == 16 的時候就已經超過1e18 了,對於每一次詢問,暴力一下就能夠c++
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 typedef long long ll; 6 7 ll n; 8 9 inline ll qpow(ll x, ll n) 10 { 11 ll ans = 1; 12 ll base = x; 13 while (n) 14 { 15 if (n & 1) ans = ans * base; 16 base = base * base; 17 n >>= 1; 18 } 19 return ans; 20 } 21 22 int main() 23 { 24 while (scanf("%lld", &n) != EOF) 25 { 26 int i; 27 for (i = 1; i <= 15; i++) 28 { 29 if (qpow(i, i) > n) 30 { 31 i--; 32 break; 33 } 34 } 35 if (i == 16) i--; 36 printf("%d\n", i); 37 } 38 }
B:Color it數組
題意:給出四種操做,數據結構
0 清空全部點ide
1 x y c 往(x, y) 處插入一個顏色爲c的點測試
2 x y1 y2 查詢(1, y1) 到(x, y2) 這個矩形裏面有多少個顏色不一樣的點優化
3 退出程序ui
思路: 很顯然 操做0 至關於多組樣例 操做3是退出程序 故咱們只須要考慮第1種操做和第2種操做spa
由於查詢的範圍當中x的左界是固定的,咱們能夠想到以y座標軸來建線段樹
由於只有51種顏色,咱們考慮建51棵線段樹,而後每次保存離左邊界最近的橫座標,看看那個y1 - y2 那個區間內是否存在一個x' < x
存在的話就有這種顏色
而後開五十棵線段樹,會爆內存,可是能夠想到,每次更新最多增長log(n)的點,操做數量的上限也才150000, 故能夠動態開點
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define INF 0x3f3f3f3f 6 #define N 1000100 7 8 struct node 9 { 10 int l, r, v; 11 inline node() 12 { 13 l = 0, r = 0, v = INF; 14 } 15 inline node(int l, int r, int v) : l(l), r(r), v(v) {} 16 }tree[N << 2]; 17 18 int root[55]; 19 int cnt, tag; 20 21 inline void Init() 22 { 23 for (int i = 0; i <= cnt; ++i) 24 tree[i] = node(); 25 memset(root, 0, sizeof root); 26 cnt = 0; 27 } 28 29 inline void update(int &id, int l, int r, int x, int y) 30 { 31 if (id == 0) 32 { 33 id = ++cnt; 34 tree[id].v = x; 35 } 36 tree[id].v = min(tree[id].v, x); 37 if (l == r) return; 38 int mid = (l + r) >> 1; 39 if (y <= mid) update(tree[id].l, l, mid, x, y); 40 else update(tree[id].r, mid + 1, r, x, y); 41 } 42 43 inline void query(int id, int l, int r, int ql, int qr, int x) 44 { 45 if (id == 0 || tag) return; 46 if (l >= ql && r <= qr) 47 { 48 if (tree[id].v <= x) 49 tag = 1; 50 return; 51 } 52 int mid = (l + r) >> 1; 53 if (ql <= mid) query(tree[id].l, l, mid, ql, min(mid, qr), x); 54 if (qr > mid) query(tree[id].r, mid + 1, r, max(ql, mid + 1), qr, x); 55 } 56 57 int main() 58 { 59 int op, x, y1, y2, c; 60 while (scanf("%d", &op) != EOF) 61 { 62 if (op == 3) return 0; 63 if (op == 0) 64 { 65 Init(); 66 } 67 if (op == 1) 68 { 69 scanf("%d%d%d", &x, &y1, &c); 70 update(root[c], 1, 1000000, x, y1); 71 } 72 if (op == 2) 73 { 74 scanf("%d%d%d", &x, &y1, &y2); 75 if (y1 > y2) swap(y1, y2); 76 int ans = 0; 77 for (int i = 0; i <= 50; ++i) 78 { 79 tag = 0; 80 query(root[i], 1, 1000000, y1, y2, x); 81 if (tag) 82 { 83 ans++; 84 } 85 } 86 printf("%d\n", ans); 87 } 88 } 89 return 0; 90 }
C:Counting Stars
題意:給出一個無向圖,沒有重邊,求有多少個"A-structure"結構。"A-structure"是指一個4個點的子圖,這4個點依次鏈接,且有一條斜邊。只要有任意一條邊或一個點不一樣,則認爲它們是不一樣的。
思路:選取一條邊做爲斜邊,統計這個斜邊上有多少個三元環,記爲sum,那麼以這個邊爲斜邊的"A-structure"共有(sum-1)*sum/2個。可是直接枚舉每條邊找環的時間複雜度在徹底圖下可達m^2的級別,
這顯然是不行的。枚舉點x,而後枚舉與x相鄰的點y,這樣至關於枚舉了每條邊,而後當x的度小於sqrt(m)時,咱們能夠用O(1)的時間判斷y是否與x其餘相鄰的點組成三元環,而當x的度大於sqrt(m)時,咱們
能夠枚舉與y相鄰的點z,用set判斷x與z是否有邊。由於m≤min(2×105,n(n−1)/2),因此度大於sqrt(m)的點不會不少,這樣時間複雜度就是msqrt(m)了。
1 #include <iostream> 2 #include <iomanip> 3 #include <fstream> 4 #include <sstream> 5 #include <cmath> 6 #include <cstdio> 7 #include <cstring> 8 #include <cctype> 9 #include <algorithm> 10 #include <functional> 11 #include <numeric> 12 #include <string> 13 #include <set> 14 #include <map> 15 #include <stack> 16 #include <vector> 17 #include <queue> 18 #include <deque> 19 #include <list> 20 using namespace std; 21 22 const int N = 100005; 23 vector<int> g[N]; 24 set<long long> p; 25 int fa[N], f[N], du[N]; 26 int main() { 27 int n, m, i, j, k, x, y; 28 long long ans, sum; 29 while (scanf("%d %d", &n, &m) != EOF) 30 { 31 ans = 0; p.clear(); 32 for (i = 1; i <= n; ++i) 33 { 34 f[i] = fa[i] = du[i] = 0; g[i].clear(); 35 } 36 for (i = 1; i <= m; ++i) 37 { 38 scanf("%d %d", &x, &y); 39 g[x].push_back(y); 40 g[y].push_back(x); 41 p.insert((long long)x*n + y); 42 p.insert((long long)y*n + x); 43 du[x]++; du[y]++; 44 } 45 for (i = 1; i <= n; ++i) 46 { 47 f[i] = 1; 48 for (j = 0; j < du[i]; ++j) fa[g[i][j]] = i; 49 for (j = 0; j < du[i]; ++j) 50 { 51 x = g[i][j]; 52 if (f[x] == 1) continue; 53 sum = 0; 54 if (du[x] <= (int) sqrt(m)) 55 { 56 for (k = 0; k < du[x]; ++k) 57 if (fa[g[x][k]] == i) sum++; 58 } 59 else 60 { 61 for (k = 0; k < du[i]; ++k) 62 if (p.find((long long)x*n + g[i][k]) != p.end()) sum++; 63 } 64 ans += (sum - 1)*sum / 2; 65 } 66 } 67 printf("%lld\n",ans); 68 } 69 return 0; 70 }
D:Covering
題意:求用 1 * 2 和 2 * 1 的方塊填充 4 * n 的矩形,求有多少方法
思路:n很大,顯然是log(n)的作法,猜想應該是矩陣快速冪遞推。用搜索或者狀壓DP暴力出前幾項,發現前幾項是這樣的
1 1
2 5
3 11
4 36
5 95
6 281
7 781
知足遞推式 F[n] = F[n - 1] + 5 * F[n - 2] + F[n - 3] - F[n - 4];
而後構造矩陣 矩陣快速冪一下
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define ll long long 6 7 const int MOD = (int)1e9 + 7; 8 9 struct node 10 { 11 ll a[4][4]; 12 inline node() 13 { 14 memset(a, 0, sizeof a); 15 } 16 inline node operator * (const node& r) const 17 { 18 node ans = node(); 19 for (int i = 0; i < 4; ++i) 20 for (int j = 0; j < 4; ++j) 21 for (int k = 0; k < 4; ++k) 22 ans.a[i][j] = (ans.a[i][j] + (a[i][k] * r.a[k][j] + MOD) % MOD + MOD) % MOD; 23 return ans; 24 } 25 }; 26 27 ll arr[4][4] = 28 { 29 1, 1, 0, 0, 30 5, 0, 1, 0, 31 1, 0, 0, 1, 32 -1, 0, 0, 0, 33 }; 34 35 inline node qpow(ll n) 36 { 37 node ans = node(); 38 ans.a[0][0] = 36, ans.a[0][1] = 11, ans.a[0][2] = 5, ans.a[0][3] = 1; 39 node base = node(); 40 for (int i = 0; i < 4; ++i) 41 for (int j = 0; j < 4; ++j) 42 base.a[i][j] = arr[i][j]; 43 while (n) 44 { 45 if (n & 1) ans = ans * base; 46 base = base * base; 47 n >>= 1; 48 } 49 return ans; 50 } 51 52 ll n; 53 54 int main() 55 { 56 while (scanf("%lld", &n) != EOF) 57 { 58 if (n == 1) puts("1"); 59 else if (n == 2) puts("5"); 60 else if (n == 3) puts("11"); 61 else if (n == 4) puts("36"); 62 else 63 { 64 node ans = qpow(n - 4); 65 printf("%lld\n", ans.a[0][0]); 66 } 67 } 68 return 0; 69 }
E:CS Course
題意:給出n個數,而後有q次查詢,每次查詢給出一個p,要求輸出這n個數中,去掉第p個數的全部數分別進行按位與運算,按位異或運算,按位或運算的和
思路:首先考慮按位異或運算,根據異或運算的性質,咱們只須要先預處理出全部數的異或和,而後每次輸出時異或一下第p個數就好了 由於這樣第p個數就異或了兩次,至關於沒有異或
再考慮按位與運算 咱們也是先處理出全部數相與以後的那個和, 而且開一個數組記錄一下每一個二進制位上爲1的數有多少, 再考慮如下幾種狀況
爲了方便,咱們假設第p個數爲A,全部數相與以後的和爲B,接下來咱們再按二進制位考慮
1° 對於某一位上,B爲0,而且A爲0,而且全部數那一位上爲1的個數爲n - 1 那麼咱們能夠知道,若是去掉A,那麼剩下的數相與,那一位上確定是1
2° 對於某一位上,B爲1,很顯然,去掉A以後,確定也會爲1
3° 對於某一位上,B爲0,而且不知足第一種狀況,那隻能爲0
按位或運算的思考方法和按位與運算思考方法差很少,此處故再也不給出。
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define N 100010 6 #define ll long long 7 8 int n, q; 9 10 ll arr[N]; 11 12 int a[60]; 13 14 int main() 15 { 16 while (scanf("%d%d", &n, &q) != EOF) 17 { 18 ll Xor = 0, And, Or = 0; 19 memset(a, 0, sizeof a); 20 for (int i = 1; i <= n; i++) 21 { 22 scanf("%lld", arr + i); 23 Xor ^= arr[i]; 24 if (i == 1) And = arr[1]; 25 else And &= arr[i]; 26 Or |= arr[i]; 27 ll tmp = arr[i]; 28 for (int j = 0; j <= 40; j++) 29 { 30 a[j + 1] += (tmp & (1ll << j)) ? 1 : 0; 31 if ((1ll << j) > tmp) break; 32 } 33 } 34 // for (int i = 0; i <= 40; i++) printf("%d%c", a[i], " \n"[i == 40]); 35 // printf("%lld %lld %lld\n", Xor, And, Or); 36 int p; 37 while (q--) 38 { 39 scanf("%d", &p); 40 ll aa = Xor ^ arr[p]; 41 ll bb = 0; ll cc = 0; 42 for (ll i = 0; i <= 40; i++) 43 { 44 if ((And & (1ll << i)) == 0 && a[i + 1] == n - 1 && (arr[p] & (1ll << i)) == 0) bb += (1ll << i); 45 else if (And & (1ll << i)) bb += (1ll << i); 46 if ((Or & (1ll << i)) && a[i + 1] == 1 && (arr[p] & (1ll << i))) continue; 47 if ((Or & (1ll << i)) == 0) continue; 48 cc += (1ll << i); 49 // printf("%lld %lld\n", bb, cc); 50 } 51 // cout << "bug\n"; 52 printf("%lld %lld %lld\n", bb, cc, aa); 53 } 54 } 55 return 0; 56 }
F:Destory Walls
題意:給出國王所在的座標,以及一些點,再給出一些邊,表示兩個點之間有一堵牆,而後國王想拆掉一些牆,使得全部區域連通,使得拆掉牆的數量最少以及花費最少,沒給出的邊就說明兩個點之間沒有牆
思路:對偶圖,是把面當作點,面與面之間連邊,那麼咱們能夠想到,若是給出的邊關係構成的圖沒有環的話,那麼只有一個面,也就是說全部區域都是連通的,那麼咱們就是想辦法留下一棵樹,使得邊數儘可能多,上面的權值和儘可能大
那就是求一棵最大生成樹
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 100010 5 #define ll long long 6 7 int n, m; 8 int pre[N]; 9 ll tot; 10 11 inline int find(int x) 12 { 13 if (pre[x] != x) 14 pre[x] = find(pre[x]); 15 return pre[x]; 16 } 17 18 struct Edge 19 { 20 int u, v; ll w; 21 inline void scan() 22 { 23 scanf("%d%d%lld", &u, &v, &w); 24 tot += w; 25 } 26 inline bool operator < (const Edge &r) const 27 { 28 return w > r.w; 29 } 30 }edge[N << 1]; 31 32 inline void Run() 33 { 34 while (scanf("%d%d", &n, &m) != EOF) 35 { 36 tot = 0; 37 for (int i = 1, x, y; i <= n; ++i) scanf("%d%d", &x, &y), pre[i] = i; 38 for (int i = 1; i <= m; ++i) edge[i].scan(); 39 sort(edge + 1, edge + 1 + m); 40 int cnt = 0; ll sum = 0; 41 for (int i = 1; i <= m; ++i) 42 { 43 int u = edge[i].u, v = edge[i].v; 44 u = find(u), v = find(v); 45 if (u == v) continue; 46 ++cnt; sum += edge[i].w; 47 pre[u] = v; 48 } 49 printf("%d %lld\n", m - cnt, tot - sum); 50 } 51 52 } 53 54 int main() 55 { 56 #ifdef LOCAL 57 freopen("Test.in", "r", stdin); 58 #endif 59 60 Run(); 61 62 return 0; 63 }
G:Duizi and Shunzi
題意: 有n個數,兩個相同的數能夠組成一個對子,三個連續的數能夠組成一個順子,數字不能夠重複使用,求最後能夠組成多少對對子和順子
思路:貪心,咱們優先的想法確定是組對子,而後再是組順子。由於組對子花的數少,組順子花的數多。
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define N 1000010 6 #define ll long long 7 8 int n; 9 10 ll arr[N]; 11 12 int main() 13 { 14 while (scanf("%d", &n) != EOF) 15 { 16 memset(arr, 0, sizeof arr); 17 for (int i = 1, num; i <= n; i++) 18 { 19 scanf("%d", &num); 20 arr[num]++; 21 } 22 ll ans = 0; 23 for (int i = 1; i <= n; ++i) 24 { 25 ans += arr[i] / 2; 26 ans += arr[i + 1] / 2; 27 arr[i] %= 2; arr[i + 1] %= 2; 28 if (arr[i] && arr[i + 1] && arr[i + 2]) 29 { 30 ans++; 31 arr[i + 2]--; 32 arr[i + 1]--; 33 } 34 } 35 printf("%lld\n", ans); 36 } 37 return 0; 38 }
H - Law of Commutation
題意:給出n和a,求有多少個b 知足 $a^b \equiv b^a \pmod m$
思路:當a是奇數的時候 答案是1(我不知道爲啥)
當a是偶數的時候 咱們令 $a = 2 \cdot x$
那麼 $a^b = 2^b \cdot x^b$
顯然 當 b > n 的時候 $a^b \equiv 0 \pmod m$
那麼當 b <= n 的時候 咱們直接暴力
當b > n的時候 若是存在答案 那麼有 $b^a \equiv 0 \pmod m$
那麼 $b^a 是 m$ 的倍數 又 $m = 2 ^ n$
因此 b 必定是 $2 ^ {\frac{n}{a}}$ (向上取整,我不知道爲啥) 的倍數
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define ll long long 5 6 int n; 7 ll a; 8 9 inline ll qpow(ll x, ll n, ll MOD) 10 { 11 ll base = x; 12 ll ans = 1; 13 while (n) 14 { 15 if (n & 1) ans = ans * base % MOD; 16 base = base * base % MOD; 17 n >>= 1; 18 } 19 return ans; 20 } 21 22 inline void Run() 23 { 24 while (scanf("%d%lld", &n, &a) != EOF) 25 { 26 if (a & 1) 27 { 28 puts("1"); 29 continue; 30 } 31 ll ans = 0; 32 ll m = 1ll << n; 33 for (int i = 1; i <= n; ++i) if (qpow(a, i, m) == qpow(i, a, m)) 34 ++ans; 35 ll tmp = (ll)ceil(n * 1.0 / a); 36 tmp = 1ll << tmp; 37 ans += (m / tmp - n / tmp); 38 printf("%lld\n", ans); 39 } 40 } 41 42 int main() 43 { 44 #ifdef LOCAL 45 freopen("Test.in", "r", stdin); 46 #endif 47 48 Run(); 49 50 return 0; 51 }
I:Matching in a Tree
留坑。
J:Query on A Tree
題意:給出一個樹,有n個結點和q次詢問,每次給出一個u和一個x,要在以結點u爲根節點的子樹中(包含u)中找出一個數與x異或後最大,輸出異或後的數
思路:子樹,天然想到用DFS序來處理這棵樹,使得全部的兒子都在連續的一段區間裏面,而後用可持久化Trie樹去找異或最大
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define N 100010 6 #define ll long long 7 8 struct Edge 9 { 10 int to, nx; 11 inline Edge() {} 12 inline Edge(int to, int nx) : to(to), nx(nx) {} 13 }edge[N << 1]; 14 15 int head[N], tot, pos, cnt; 16 int fa[N], son[N], ord[N], ford[N]; 17 int root[N]; 18 19 struct node 20 { 21 int son[2], Count; 22 inline node() 23 { 24 memset(son, 0, sizeof son); 25 Count = 0; 26 } 27 }tree[N * 64]; 28 29 inline void Init() 30 { 31 memset(head, -1, sizeof head); 32 pos = 0; tot = 0, cnt = 0; 33 tree[0] = node(); 34 } 35 36 inline void addedge(int u, int v) 37 { 38 edge[++tot] = Edge(v, head[u]); head[u] = tot; 39 } 40 41 int n, q; 42 ll w[N]; 43 44 inline void DFS(int u) 45 { 46 ord[u] = ++pos; 47 ford[pos] = u; 48 for (int it = head[u]; ~it; it = edge[it].nx) 49 { 50 int v = edge[it].to; 51 if (v == fa[u]) continue; 52 DFS(v); 53 } 54 son[u] = pos; 55 } 56 57 inline void Insert(ll x, int id) 58 { 59 bitset <32> b; b = x; 60 root[id] = ++cnt; 61 tree[cnt] = tree[root[id - 1]]; 62 int poss = cnt; 63 for (int i = 31; i >= 0; --i) 64 { 65 int index = b[i]; 66 tree[++cnt] = tree[tree[poss].son[index]]; 67 tree[cnt].Count++; 68 tree[poss].son[index] = cnt; 69 poss = cnt; 70 } 71 } 72 73 inline ll Query(ll x, int l, int r) 74 { 75 bitset <32> b; b = x; 76 ll ans = 0; 77 l = root[l], r = root[r]; 78 for (int i = 31; i >= 0; --i) 79 { 80 int index = b[i] ^ 1; 81 bool flag = true; 82 if (tree[tree[r].son[index]].Count - tree[tree[l].son[index]].Count <= 0) 83 { 84 index ^= 1; 85 flag = false; 86 } 87 if (flag) ans += (1 << i); 88 r = tree[r].son[index]; l = tree[l].son[index]; 89 } 90 return ans; 91 } 92 93 int main() 94 { 95 while (scanf("%d%d", &n, &q) != EOF) 96 { 97 Init(); 98 for (int i = 1; i <= n; ++i) scanf("%lld", w + i); 99 for (int i = 1, u; i < n; ++i) 100 { 101 scanf("%d", &u); 102 fa[i + 1] = u; 103 addedge(u, i + 1); 104 } 105 DFS(1); 106 for (int i = 1; i <= n; ++i) 107 { 108 Insert(w[ford[i]], i); 109 } 110 while(q--) 111 { 112 int u; ll x; 113 scanf("%d%lld",&u,&x); 114 int l = ord[u] - 1, r = son[u]; 115 printf("%lld\n",Query(x, l, r)); 116 } 117 } 118 return 0; 119 }
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 typedef long long ll; 5 6 const int N = 2e5 + 10; 7 8 vector<int>G[N]; 9 10 int n, q; 11 12 int ord[N], son[N], v[N], get_ord[N]; 13 int index; 14 15 int trie[N * 35][2], latest[N * 35]; 16 int root[N], tot; 17 18 inline void init() 19 { 20 memset(trie, 0, sizeof trie); 21 memset(latest, 0, sizeof latest); 22 memset(root, 0, sizeof root); 23 tot = 0; 24 index = 0; 25 for (int i = 0; i < N; ++i) 26 { 27 G[i].clear(); 28 } 29 } 30 31 inline void insert(int i, int k, int p, int q) 32 { 33 if (k < 0) 34 { 35 latest[q] = i; 36 return; 37 } 38 int c = v[get_ord[i]] >> k & 1; 39 if (p) trie[q][c ^ 1] = trie[p][c ^ 1]; 40 trie[q][c] = ++tot; 41 insert(i, k - 1, trie[p][c], trie[q][c]); 42 latest[q] = max(latest[trie[q][0]], latest[trie[q][1]]); 43 } 44 45 inline int query(int now, int val, int k, int limit) 46 { 47 if (k < 0) 48 { 49 return v[get_ord[latest[now]]] ^ val; 50 } 51 int c = val >> k & 1; 52 if (latest[trie[now][c ^ 1]] >= limit) 53 return query(trie[now][c ^ 1], val, k - 1, limit); 54 else 55 return query(trie[now][c], val, k - 1, limit); 56 } 57 58 inline void dfs(int u) 59 { 60 ord[u] = ++index; 61 get_ord[index] = u; 62 for (int i = 0; i < G[u].size(); i++) 63 { 64 int to = G[u][i]; 65 dfs(to); 66 } 67 son[u] = index; 68 } 69 70 int main() 71 { 72 while (~scanf("%d %d", &n, &q)) 73 { 74 init(); 75 latest[0] = -1; 76 root[0] = ++tot; 77 insert(0, 30, 0, root[0]); 78 for (int i = 1; i <= n; ++i) 79 { 80 scanf("%d", &v[i]); 81 } 82 for (int i = 2, u; i <= n; ++i) 83 { 84 scanf("%d", &u); 85 G[u].push_back(i); 86 } 87 dfs(1); 88 for (int i = 1; i <= n; ++i) 89 { 90 root[i] = ++tot; 91 insert(i, 30, root[i - 1], root[i]); 92 } 93 while (q--) 94 { 95 int u, x; 96 scanf("%d %d", &u, &x); 97 printf("%d\n", query(root[son[u]], x, 30, ord[u])); 98 } 99 } 100 return 0; 101 }
K:Removing Mountains
留坑。
L:Yuno And lrotoridori no Sekai
按題意暴力模擬
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 1000010 5 6 struct Edge 7 { 8 int to, nx; 9 inline Edge() {} 10 inline Edge(int to, int nx) : to(to), nx(nx) {} 11 }edge[N << 1]; 12 13 int n, q; 14 int head[N], pos; 15 int w[N], path[N], deep[N], fa[N], tot; 16 int rmq[N << 1], F[N << 1], P[N << 1], cnt; 17 vector <int> vec; 18 19 struct ST 20 { 21 int mm[N << 1]; 22 int dp[N << 1][20]; 23 inline void init(int n) 24 { 25 mm[0] = -1; 26 for (int i = 1; i <= n; ++i) 27 { 28 mm[i] = ((i & (i - 1)) == 0) ? mm[i - 1] + 1 : mm[i - 1]; 29 dp[i][0] = i; 30 } 31 for (int j = 1; j <= mm[n]; ++j) 32 { 33 for (int i = 1; i + (1 << j) - 1 <= n; ++i) 34 { 35 dp[i][j] = rmq[dp[i][j - 1]] < rmq[dp[i + (1 << (j - 1))][j - 1]] ? dp[i][j - 1] : dp[i + (1 << (j - 1))][j - 1]; 36 } 37 } 38 } 39 inline int query(int a, int b) 40 { 41 if (a > b) swap(a, b); 42 int k = mm[b - a + 1]; 43 return rmq[dp[a][k]] <= rmq[dp[b - (1 << k) + 1][k]] ? dp[a][k] : dp[b - (1 << k) + 1][k]; 44 } 45 }st; 46 47 inline void Init() 48 { 49 memset(head, -1, sizeof head); 50 pos = 0; deep[1] = 0; fa[1] = 1; 51 } 52 53 inline void addedge(int u, int v) 54 { 55 edge[++pos] = Edge(v, head[u]); head[u] = pos; 56 edge[++pos] = Edge(u, head[v]); head[v] = pos; 57 } 58 59 inline void DFS(int u) 60 { 61 deep[u] = deep[fa[u]] + 1; 62 F[++cnt] = u; 63 rmq[cnt] = deep[u]; 64 P[u] = cnt; 65 for (int it = head[u]; ~it; it = edge[it].nx) 66 { 67 int v = edge[it].to; 68 if (v == fa[u]) continue; 69 fa[v] = u; 70 DFS(v); 71 F[++cnt] = u; 72 rmq[cnt] = deep[u]; 73 } 74 } 75 76 inline void LCA_Init(int root, int node_num) 77 { 78 cnt = 0; 79 DFS(root); 80 st.init(2 * node_num - 1); 81 } 82 83 inline int query_lca(int u, int v) 84 { 85 return F[st.query(P[u], P[v])]; 86 } 87 88 inline void query(int u) 89 { 90 vec.clear(); vec.push_back(w[u]); 91 for (int it = head[u]; ~it; it = edge[it].nx) 92 { 93 int v = edge[it].to; 94 vec.emplace_back(w[v]); 95 } 96 sort(vec.begin(), vec.end()); 97 } 98 99 inline void Get(int u, int v) 100 { 101 int lca = query_lca(u, v); 102 tot = 0; 103 path[++tot] = u; 104 while (u != lca) 105 { 106 u = fa[u]; 107 path[++tot] = u; 108 } 109 int mid = tot; 110 while (v != lca) 111 { 112 path[++tot] = v; 113 v = fa[v]; 114 } 115 reverse(path + 1 + mid, path + 1 + tot); 116 } 117 118 inline void add(int v) 119 { 120 for (int i = 1; i <= tot; ++i) 121 w[path[i]] += v; 122 } 123 124 inline void Reverse() 125 { 126 for (int i = 1, j = tot; i < j; ++i, --j) 127 swap(w[path[i]], w[path[j]]); 128 } 129 130 inline void Run() 131 { 132 while (scanf("%d%d", &n, &q) != EOF) 133 { 134 Init(); 135 for (int i = 1; i <= n; ++i) scanf("%d", w + i); 136 for (int i = 1, u, v; i < n; ++i) 137 { 138 scanf("%d%d", &u, &v); 139 addedge(u, v); 140 } 141 LCA_Init(1, n); 142 int op, x, y, z; 143 while (q--) 144 { 145 scanf("%d%d%d", &op, &x, &y); 146 if (op == 3) 147 { 148 query(x); 149 while (y--) 150 { 151 scanf("%d", &x); 152 printf("%d\n", vec[x - 1]); 153 } 154 } 155 else 156 { 157 Get(x, y); 158 if (op == 1) 159 Reverse(); 160 else 161 { 162 scanf("%d", &z); 163 add(z); 164 } 165 } 166 } 167 } 168 } 169 170 int main() 171 { 172 #ifdef LOCAL 173 freopen("Test.in", "r", stdin); 174 #endif 175 176 Run(); 177 178 return 0; 179 }
賽後總結: