ZOJ-4028 LIS (差分约束)
题目链接:ZOJ-4028 LIS
题意
有一个长度为 \(n\ (1\le n \le 10^5)\) 的序列 \(a\),对于所有的 \(i\in [1,n]\) ,已知 \(f_i,\ l_i,\ r_i\) ,代表序列 \(a\) 中末尾元素为 \(a_i\) 的最长上升子序列长度为 \(f_i\) ,且 \(l_i \le a_i \le r_i\) ,求序列 \(a\) 。
思路
找出 \(a_i\) 的所有约束条件:
- 记 \(i'\) 为 \(i\) 前面满足 \(f_{i'}=f_i\) 的离 \(i\) 最近的位置,\(a_i\) 的值需要满足 \(a_i \le a_{i'}\) ;
- 记 \(i''\) 为 \(i\) 前面满足 \(f_{i''}+1=f_i\) 的离 \(i\) 最近的位置,\(a_i\) 的值需要满足 \(a_i>a_{i''}\) ;
- \(l_i\le a_i\le r_i\) 。
知道了每个 \(a_i\) 的约束条件,可以用差分约束求解(用 \(e(u,v,w)\) 代表从 \(u\) 到 \(v\) 权值为 \(w\) 的有向边):
- \(a_i\le a_{i'}\) 可变形为 \(a_i\le a_{i'}+0\) ,连边 \(e(i',i,0)\) ;
- \(a_i>a_{i''}\) 可变形为 \(a_{i''}\le a_i-1\) ,连边 \(e(i,i'',-1)\) ;
- 新增一个源点 \(s\),令 \(a_s=0\) 。\(l_i\le a_i\le r_i\) 可变形为 \(a_s\le a_i-l_i,\ a_i\le a_s+r_i\) ,连边 \(e(i,s,-l_i),\ e(s,i,r_i)\) 。
建完图跑差分约束即可。
代码实现
#include <cstdio>
#include <cstring>
#include <queue>
using std::queue;
typedef long long LL;
const int maxn = 100010;
int head[maxn], tot;
LL dist[maxn];
int f[maxn], last[maxn];
bool inq[maxn];
struct Edge{
int to, nex, val;
} edge[maxn<<2];
void add_edge(int u, int v, int w) {
edge[++tot].nex = head[u];
edge[tot].to = v;
edge[tot].val = w;
head[u] = tot;
}
void bfs_spfa(int s, int n) {
memset(inq, 0, sizeof(bool) * (n+5));
memset(dist, 0x3f, sizeof(LL) * (n+5));
queue<int> que;
que.push(s);
inq[s] = true;
dist[s] = 0;
while (!que.empty()) {
int u = que.front();
que.pop();
inq[u] = false;
for (int i = head[u]; i; i = edge[i].nex) {
int v = edge[i].to;
if (dist[v] > dist[u] + edge[i].val) {
dist[v] = dist[u] + edge[i].val;
if (!inq[v]) {
inq[v] = true;
que.push(v);
}
}
}
}
for (int i = 1; i <= n; i++) printf("%lld%c", dist[i], " \n"[i==n]);
}
int main() {
int T, n;
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
memset(last, 0, sizeof(int) * (n+5));
memset(head, 0, sizeof(int) * (n+5));
tot = 0;
for (int i = 1; i <= n; i++) {
scanf("%d", &f[i]);
if (last[f[i]]) add_edge(last[f[i]], i, 0);
if (f[i] > 1) add_edge(i, last[f[i]-1], -1);
last[f[i]] = i;
}
for (int i = 1, l, r; i <= n; i++) {
scanf("%d %d", &l, &r);
add_edge(0, i, r);
add_edge(i, 0, -l);
}
bfs_spfa(0, n);
}
return 0;
}
作者:_kangkang
本文版权归作者和博客园共有,欢迎转载,但必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。