[POI2015]PUS
题面:Luogu
题解:线段树优化建图+差分约束+toposort
可以发现\([l,r]\)区间被分成了\(k+1\)段区间
然后发现这是典型的差分约束,从区间向单点连边
大概就是建一颗出树
每一次区间连边,就把这些区间对应的点连向一个新建的虚拟节点,然后再从这个节点连向对应位置
具体看代码
我也不知道为什么这道题要上拓扑排序,按理来讲应该可以全连向虚拟节点然后跑spfa啊?
大概是因为边权为0/1?
求最长路可以在拓扑排序中完成
#include<bits/stdc++.h>
using namespace std;
inline void read(int& x)
{
x = 0; char c = getchar(); int f = 1;
while (!isdigit(c)) { if (c == '-') f = -1; c = getchar(); }
while (isdigit(c)) x = x * 10 + c - '0', c = getchar();
x *= f;
}
#define maxn 1000005
const int lim = 1e9;
struct Edge
{
int fr, to, val;
}eg[maxn << 1];
int head[maxn], edgenum, deg[maxn];
inline void add(int fr, int to, int val)
{
eg[++edgenum] = { head[fr],to,val };
head[fr] = edgenum; ++deg[to];
}
int n, s, m;
int root[maxn], tot;
#define ls rt<<1
#define rs rt<<1|1
void build(int rt, int l, int r)
{
if (l == r) { root[rt] = l; return; }
int mid = (l + r) >> 1;
root[rt] = ++tot;
build(ls, l, mid), build(rs, mid + 1, r);
add(root[ls], root[rt], 0), add(root[rs], root[rt], 0);
}
void link(int rt, int l, int r, int fr, int to, int To)
{
if (fr <= l && to >= r) return add(root[rt], To, 0);
int mid = (l + r) >> 1;
if (fr <= mid) link(ls, l, mid, fr, to, To);
if (to > mid) link(rs, mid + 1, r, fr, to, To);
}
int dis[maxn], a[maxn], vis[maxn];
#define to eg[i].to
void Toposort()
{
queue<int> q;
for (int i = 1; i <= tot; ++i)
{
if (!deg[i]) q.push(i);
if (!dis[i]) dis[i] = 1;//如果这一点没有值,就初始化为1
}
while (!q.empty())
{
int tp = q.front(); q.pop(); vis[tp] = 1;
for (int i = head[tp]; i; i = eg[i].fr)
{
dis[to] = max(dis[to], dis[tp] + eg[i].val);
if (a[to] && dis[to] > a[to]) puts("NIE"), exit(0);
if (!--deg[to]) q.push(to);
}
}
}
int main()
{
int n, s, m;
read(n), read(s), read(m), tot = n;
build(1, 1, n);
for (int i = 1, pos, val; i <= s; ++i)
read(pos), read(val), a[pos] = dis[pos] = val;
for (int i = 1, l, r, k, las; i <= m; ++i)
{
read(l), read(r), read(k);
las = l - 1, ++tot;
for (int j = 1, tp; j <= k; ++j)
{
read(tp);
add(tot, tp, 1);//tp向这个区间连边,表示tp比这些至少大1(严格大于)
if (tp > las + 1) link(1, 1, n, las + 1, tp - 1, tot);
las = tp;
}
if (las < r) link(1, 1, n, las + 1, r, tot);
}
Toposort();
for (int i = 1; i <= tot; ++i)
if (!vis[i] || dis[i] > lim) puts("NIE"), exit(0);//注意lim的限制
puts("TAK");
for (int i = 1; i <= n; ++i) printf("%d ", dis[i]);
return 0;
}
一切伟大的行动和思想,都有一个微不足道的开始。
There is a negligible beginning in all great action and thought.
There is a negligible beginning in all great action and thought.