圖論/主席樹優化建圖-小火車什麼什麼三維宇宙
阿新 • • 發佈:2018-12-24
題目大意:給 \(n\ (n\le 100,000)\) 個三元組,保證每個數每一維構成 \([1,n]\) 的排列,定義大於表示一個數至少兩維比另一個數大,求某個順序比較之後可能是最大的數的數具體是哪些。
大於不具有傳遞性。
入度為 \(0\) 的點一定可以是最大值,只要從這個點開始,每次隨便找一個其他點比較就行。
如果有環,考慮最終讓 \(a_i\) 作為最大值,只要從大於 \(a_i\) 的 \(a_k\) 開始,與大於 \(a_k\) 的 \(a_t\) 比較,得到當前最大值 \(a_t\) ,繼續……最後再與 \(a_i\) 比較即可。
所以環上任意點都可以是最大值。
兩個數不是 \(a>b\)
列舉“至少兩維”中是哪兩維,然後連邊。如果升序討論 \(x_i\) ,則應連向 \(y_t < x_i,\ x_t < x_i\) 的數。第一個限制,對 \(y\) 開權值線段樹。第二個限制,把線段樹開成可持久化的,每次新增完邊後,再新增一條從根節點到 \(y_i\) 號葉子節點,並從葉子連向對應數的路徑。
Tarjan 寫錯變數名調了半天 Orz 。
#include <cstdio> #include <ctype.h> #include <cmath> #include <algorithm> using namespace std; char *p1, *p2, buf[1 << 20]; inline char gc() { return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 20, stdin), p1 == p2) ? EOF : *p1++; } template<typename T> void rd(T &num) { char tt; bool flag = 0; while (!isdigit(tt = gc()) && tt != '-'); if (tt == '-') num = 0, flag = 1; else num = tt - '0'; while (isdigit(tt = gc())) num = num * 10 + tt - '0'; if (flag) num = -num; return; } const int _N = 101000; const int _M = 13500000; typedef int lar[_M]; int EC, FK, N, ST_cnt, Stamp, S_cnt, SCC; int B[_N], X[_N], Y[_N], Z[_N], Rt[_N]; lar Nxt, Fst, V, Fk_nxt, Fk_fst, Fk_v, L, R, Low, Dfn, S, Bel, Ind, Q; bool Mk[_M]; void ins_edge(int a, int b) { if (!a || !b) return; ++EC, Nxt[EC] = Fst[a], Fst[a] = EC, V[EC] = b; return; } void fuck_edge(int a, int b) { ++FK, Fk_nxt[FK] = Fk_fst[a], Fk_fst[a] = FK, Fk_v[FK] = b; return; } void ins_path(int &p, int &q, int l, int r, int num, int val) { p = ++ST_cnt; if (l == r) { ins_edge(p, num); return; } int mid = (l + r) >> 1; if (val <= mid) R[p] = R[q], ins_path(L[p], L[q], l, mid, num, val); else L[p] = L[q], ins_path(R[p], R[q], mid + 1, r, num, val); ins_edge(p, L[p]), ins_edge(p, R[p]); return; } void connect(int &p, int l, int r, int num, int s, int t) { if (s > t || !p) return; if (s <= l && r <= t) { ins_edge(num, p); return; } int mid = (l + r) >> 1; if (s <= mid) connect(L[p], l, mid, num, s, t); if (t > mid) connect(R[p], mid + 1, r, num, s, t); return; } void owo(int *x, int *y) { for (int i = 1; i <= N; ++i) B[x[i]] = i; Rt[0] = 0; for (int i = 1; i <= N; ++i) { connect(Rt[i - 1], 1, N, B[i], 1, y[B[i]] - 1); ins_path(Rt[i], Rt[i - 1], 1, N, B[i], y[B[i]]); } return; } void dfs(int p) { Low[p] = Dfn[p] = ++Stamp, Mk[p] = 1, S[++S_cnt] = p; for (int i = Fst[p]; i; i = Nxt[i]) { int &t = V[i]; if (!Dfn[t]) dfs(t), Low[p] = min(Low[p], Low[t]); else if (Mk[t]) Low[p] = min(Low[p], Dfn[t]); } if (Low[p] != Dfn[p]) return; int tmp; ++SCC; do { tmp = S[S_cnt--], Mk[tmp] = 0, Bel[tmp] = SCC; } while (tmp != p); return; } int main() { rd(N); for (int i = 1; i <= N; ++i) rd(X[i]), rd(Y[i]), rd(Z[i]); ST_cnt = N; owo(X, Y), owo(X, Z), owo(Y, Z); for (int i = 1; i <= ST_cnt; ++i) if (!Dfn[i]) dfs(i); for (int i = 1; i <= ST_cnt; ++i) for (int j = Fst[i]; j; j = Nxt[j]) { int &t = V[j]; if (Bel[i] != Bel[t]) fuck_edge(Bel[i], Bel[t]), ++Ind[Bel[t]]; } for (int i = 1; i <= N; ++i) Mk[Bel[i]] = 1; int hd = 1, tl = 1, ans = -1; for (int i = 1; i <= SCC; ++i) if (!Ind[i]) Q[tl++] = i; while (hd < tl) { int p = Q[hd++]; if (Mk[p]) { ans = p; break; } for (int i = Fk_fst[p]; i; i = Fk_nxt[i]) { int &t = Fk_v[i]; if (!--Ind[t]) Q[tl++] = t; } } for (int i = 1; i <= N; ++i) printf("%d\n", Bel[i] == ans); return 0; }