【題解】[CEOI2020]權力藥水
阿新 • • 發佈:2021-06-22
題意不是很複雜,只不過出題人強行把題面寫的很長。
首先 \(D\) 很小,所以對於每個詢問,我們可以直接找出兩個人信任的人的集合,然後雙指標掃一遍即可。
對詢問離線,然後維護每個人的集合即可,這道題就做完了(
但是本題強制線上,把小清新模擬題強行變成毒瘤題。
我們需要記錄,每個人,在每一時刻,信任的人的集合,這複雜度是 \(\mathcal{O}(NMD)\) 的,顯然不行。
考慮對每個人動態開點,那麼剩下的狀態數是 \(\mathcal{O}(MD)\) 還是吃不消。
\(M\) 比較大,將時間作為動態開點的下標,那麼對於一個關係 \((x,y)\),可以計算出它在圖中存活的時間段,然後線上段樹中區間加。
因為是動態開點線段樹,所以我們需要標記永久化。最後線上段樹上單點查詢即可得到集合,排序後跑雙指標得到答案。
時間複雜度 \(\mathcal{O}(M\log M+QD\log D)\)。另外本題卡空間,觀察一下發現不少關係 \((x,y)\) 的存活時間都是從某個時間開始,一直持續到結束。對於這類關係,我們直接對每個點開一個變長陣列維護即可。因為這類關係對每個點的貢獻也不會超過 \(D\)。
#include <bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=b;i++) #define pre(i,a,b) for(int i=a;i>=b;i--) #define N 100005 #define ef 1000000000 using namespace std; struct node { int l, r; vector<int>u; } a[N * 55]; #define ls a[x].l #define rs a[x].r #define S a[x].u int n, D, m, q, u[N], rt[N], idx; void ins(int &x, int l, int r, int L, int R, int val) { if (!x) x = ++idx; if (L >= l && R <= r) { a[x].u.push_back(val); return ; } int mid = (L + R) >> 1; if (mid >= l) ins(ls, l, r, L, mid, val); if (mid < r) ins(rs, l, r, mid + 1, R, val); } vector<int>c[2]; void ask(int x, int L, int R, int pos, int op) { if (!x) return; for (int i = 0; i < (int)a[x].u.size(); i++) c[op].push_back(a[x].u[i]); if (L == R) return; int mid = (L + R) >> 1; if (mid >= pos) ask(ls, L, mid, pos, op); else ask(rs, mid + 1, R, pos, op); } vector<pair<int, int>>ad[N]; map<pair<int, int>, int>h; inline void calc() { int p = c[0].size(), q = c[1].size(); if (!p || !q) { cout << ef << endl; return; } sort(c[0].begin(), c[0].end()); sort(c[1].begin(), c[1].end()); int j = 0, mn = 0x7fffffff; rep(i, 0, q - 1) { while (j < p - 1 && c[0][j] <= c[1][i]) j++; mn = min(mn, abs(c[0][j] - c[1][i])); if (j) mn = min(mn, abs(c[0][j - 1] - c[1][i])); } cout << mn << endl; } int main() { scanf("%d%d%d%d", &n, &D, &m, &q); rep(i, 1, n)scanf("%d", &u[i]); rep(i, 1, m) { int x, y; scanf("%d%d", &x, &y); x++, y++; if (x > y) swap(x, y); pair<int, int> cur = make_pair(x, y); if (h.count(cur)) { ins(rt[x], h[cur], i - 1, 1, m, u[y]); ins(rt[y], h[cur], i - 1, 1, m, u[x]); h.erase(h.find(cur)); } else h.insert(make_pair(cur, i)); } for (map<pair<int, int>, int>::iterator it = h.begin(); it != h.end(); it++) { int x = (*it).first.first, y = (*it).first.second; ad[x].push_back(make_pair(u[y], (*it).second)); ad[y].push_back(make_pair(u[x], (*it).second)); } while (q--) { int x, y, z; scanf("%d%d%d", &x, &y, &z); x++, y++; c[0].clear(); c[1].clear(); if (z) { ask(rt[x], 1, m, z, 0), ask(rt[y], 1, m, z, 1); for (int i = 0; i < (int)ad[x].size(); i++) if (ad[x][i].second <= z) c[0].push_back(ad[x][i].first); for (int i = 0; i < (int)ad[y].size(); i++) if (ad[y][i].second <= z) c[1].push_back(ad[y][i].first); calc(); } else cout << ef << endl; } return 0; }