图论/主席树优化建图-小火车什么什么三维宇宙
题目大意:给 \(n\ (n\le 100,000)\) 个三元组,保证每个数每一维构成 \([1,n]\) 的排列,定义大于表示一个数至少两维比另一个数大,求某个顺序比较之后可能是最大的数的数具体是哪些。
大于不具有传递性。
入度为 \(0\) 的点一定可以是最大值,只要从这个点开始,每次随便找一个其他点比较就行。
如果有环,考虑最终让 \(a_i\) 作为最大值,只要从大于 \(a_i\) 的 \(a_k\) 开始,与大于 \(a_k\) 的 \(a_t\) 比较,得到当前最大值 \(a_t\) ,继续……最后再与 \(a_i\) 比较即可。
所以环上任意点都可以是最大值。
两个数不是 \(a>b\) 就是 \(a<b\) ,即两点间一定有边,所以缩点之后入度为 \(0\) 的强连通分量只有一个。
枚举“至少两维”中是哪两维,然后连边。如果升序讨论 \(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;
}