Address
https://www.lydsy.com/JudgeOnline/problem.php?id=4383
Solution
可以想到,如果对于 i,j i , j 要求满足 a[i]>a[j] a [ i ] > a [ j ] 的约束,就建边 <i,j> < i , j > ,建图后拓扑排序,如果有环就无解。
但要解决两个问题:
(1)已经钦定的数值。
我们可以把第 i i 个数尽量填成能填的最大的数(如果入度为 0 0 且未被钦定就填 109 10 9 )。
这个可以在拓扑排序上 dp 得到。
(2)建图的复杂度问题。
考虑优化建图。由于 ∑k ∑ k 不大,所以对每个限制建一个虚拟节点,把 k k 个点连到虚拟节点上,再把虚拟节点向 [l,r] [ l , r ] 内除掉这 k k 个位置剩下的 O(k) O ( k ) 个区间内的点连边。
一个点向一个区间连边,可以使用线段树优化建图来实现。
Code
#include <cmath>
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
using namespace std;
inline int read() {
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
const int N = 1e6 + 5, INF = 1e9;
int n, s, m, to[N], val[N], lc[N], rc[N], nm = 1, ps[N],
H, T, Q[N], cnt[N];
bool ch[N];
vector<int> eg[N], rp[N];
void add_edge(int u, int v, int w) {
eg[u].push_back(v); rp[u].push_back(w); cnt[v]++;
}
void build(int l, int r, int p) {
if (l == r) return (void) (to[l] = p);
int mid = l + r >> 1;
lc[p] = ++nm; build(l, mid, lc[p]);
rc[p] = ++nm; build(mid + 1, r, rc[p]);
add_edge(p, lc[p], 0); add_edge(p, rc[p], 0);
}
void linkedge(int u, int l, int r, int s, int e, int p) {
if (l == s && r == e) return (void) (add_edge(u, p, 1));
int mid = l + r >> 1;
if (e <= mid) linkedge(u, l, mid, s, e, lc[p]);
else if (s >= mid + 1) linkedge(u, mid + 1, r, s, e, rc[p]);
else linkedge(u, l, mid, s, mid, lc[p]),
linkedge(u, mid + 1, r, mid + 1, e, rc[p]);
}
int main() {
int i, l, r, k;
n = read(); s = read(); m = read();
build(1, n, 1);
while (s--) {
l = read(); r = read();
if (r < 1 || r > INF) return puts("NIE"), 0;
val[to[l]] = r; ch[to[l]] = 1;
}
while (m--) {
nm++;
l = read(); r = read(); k = read();
For (i, 1, k) ps[i] = read(),
add_edge(to[ps[i]], nm, 0);
if (l < ps[1]) linkedge(nm, 1, n, l, ps[1] - 1, 1);
if (ps[k] < r) linkedge(nm, 1, n, ps[k] + 1, r, 1);
For (i, 1, k - 1) if (ps[i] + 1 < ps[i + 1])
linkedge(nm, 1, n, ps[i] + 1, ps[i + 1] - 1, 1);
}
For (i, 1, nm) if (!val[i]) val[i] = INF;
For (i, 1, nm) if (!cnt[i]) Q[++T] = i;
while (H < T) {
int u = Q[++H], otz = eg[u].size();
For (i, 0, otz - 1) {
int v = eg[u][i], w = rp[u][i];
if (!(--cnt[v])) Q[++T] = v;
if (ch[v] && val[u] - w < val[v]) return puts("NIE"), 0;
if (ch[v]) continue;
val[v] = min(val[v], val[u] - w);
if (val[v] < 1) return puts("NIE"), 0;
}
}
if (T < nm) return puts("NIE"), 0;
puts("TAK");
For (i, 1, n) printf("%d ", val[to[i]]);
cout << endl;
return 0;
}