题意:给你一组最长上升子序列的dp区间值,然后给你每个点的取值范围,求可行的原序列
首先满足l[i] <= a[i] <= r[i], 可以建一个源点 n+1,那么有
a[n+1] - a[i] <= -l[i], a[i] - a[n+1] <= r[i]
对于之前出现过a[i]的点 j,要使a[i]>=a[j](保证没法转移), 有
a[j] - a[i] <= 0
还有对于从上一个a[i]-1转移过来的点 j, 要使a[i] > a[j],有
a[j] - a[i] <= -1
跑一边最短路,d[i] 即为所求
0x3f3f3f3f 作为最大值wa了 ??? 大一点好吧。。。
链接:zoj 4028
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <set>
#include <map>
#include <stack>
#include <queue>
#define inf 0x7f7f7f7f
using namespace std;
const int maxn = 100005;
const int maxm = 1000050;
int n = maxn, m, s, t; //n为点数 s为源点
int head[maxn]; //head[from]表示以head为出发点的邻接表表头在数组es中的位置,开始时所有元素初始化为-1
long long d[maxn]; //储存到源节点的距离,在Spfa()中初始化
int cnt[maxn];
bool inq[maxn]; //这里inq作inqueue解释会更好,出于习惯使用了inq来命名,在Spfa()中初始化
int nodep; //在邻接表和指向表头的head数组中定位用的记录指针,开始时初始化为0
int pre[maxn];
struct node {
int v, w, next;
}es[maxm];
void init() {
for(int i = 0; i <= n + 1; i++) {
d[i] = inf;
inq[i] = false;
cnt[i] = 0;
head[i] = -1;
pre[i] = -1;
}
nodep = 0;
}
void addedge(int from, int to, int weight)
{
es[nodep].v = to;
es[nodep].w = weight;
es[nodep].next = head[from];
head[from] = nodep++;
}
bool spfa()
{
queue<int> que;
d[s] = 0; //s为源点
inq[s] = 1;
que.push(s);
while(!que.empty()) {
int u = que.front();
que.pop();
inq[u] = false; //从queue中退出
//遍历邻接表
for(int i = head[u]; i != -1; i = es[i].next) { //在es中,相同from出发指向的顶点为从head[from]开始的一项,逐项使用next寻找下去,直到找到第一个被输
//入的项,其next值为-1
int v = es[i].v;
if(d[v] > d[u] + es[i].w) { //松弛(RELAX)操作
d[v] = d[u] + es[i].w;
//pre[v] = u;
if(!inq[v]) { //若被搜索到的节点不在队列que中,则把to加入到队列中去
inq[v] = true;
que.push(v);
}
}
}
}
return true;
}
int l[maxn], r[maxn];
int a[maxn];
int last[maxn];
int main()
{
int T, kcase = 0, k;
scanf("%d", &T);
while(T--) {
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
for(int i = 1; i <= n; i++) {
scanf("%d %d", &l[i], &r[i]);
}
s = n + 1;
init();
memset(last, 0, sizeof(last));
for(int i = 1; i <= n; i++) {
addedge(s, i, r[i]);
addedge(i, s, -l[i]);
if(last[a[i]]) {
addedge(last[a[i]], i, 0);
}
if(a[i] > 0) {
addedge(i, last[a[i] - 1], -1);
}
last[a[i]] = i;
}
spfa();
bool flag = 1;
for(int i = 1; i <= n; i++) {
if(flag)printf("%lld", d[i]);
else printf(" %lld",d[i]);
flag = 0;
}
puts("");
}
return 0;
}