题意:给你每个位置以该位置结尾的最长上升子序列的值,然后给你每个点的取值范围,求可行的原序列
题解: 我们另 源点 为 (n+1)点
1. 因为对于每个a[i] 满足 l[i] <= a[i] <= r[i] 所以 转换为 (n+1) -a[i] <= -l[i] a[i] - (n+1) <= r[i]
2. 若i点最长上升子序列为 k 那么他要比前面为k 的数小于等于 ,pre[k] 表示之前 该值出现的位置 则:a[i] - a[pre[k]] <= 0
3. 若i点最长上升子序列为 k,那么他要比之前出现 k-1 位置 的数大 即:a[i] - a[pre[k - 1]] >= 1 即:a[pre[k - 1]] - a[i] <= -1
线性约束条件找好,建图,从原点跑最短路即可
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int N=1e5+10;
typedef long long ll;
#define INF 0x7f7f7f7f
struct node
{
int to,nex,d;
}e[N*10];
int head[N],vis[N],len,pre[N];
ll dis[N];
int n,l[N],r[N],f[N];
void init()
{
len=0;
for(int i=0;i<=n+1;i++)
{
head[i]=-1;
dis[i]=INF;
vis[i]=0;
pre[i]=0;
}
}
void add(int u,int v,int d)
{
e[len].to=v;
e[len].d=d;
e[len].nex=head[u];
head[u]=len++;
}
void spfa(int s)
{
int u,to;
queue<int> q;
dis[s]=0;
vis[s]=1;
q.push(s);
while(!q.empty())
{
u=q.front();q.pop();
vis[u]=0;
for(int i=head[u];i!=-1;i=e[i].nex)
{
to=e[i].to;
if(dis[to]>dis[u]+e[i].d)
{
dis[to]=dis[u]+e[i].d;
if(!vis[to]) q.push(to),vis[to]=1;
}
}
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&f[i]);
init();
for(int i=1;i<=n;i++)
{
scanf("%d%d",&l[i],&r[i]);
add(i,n+1,-l[i]);
add(n+1,i,r[i]);
add(i,pre[f[i]-1],-1);
if(pre[f[i]]) add(pre[f[i]],i,0);
pre[f[i]]=i;
}
spfa(n+1);
for(int i=1;i<=n;i++)printf("%lld%c",dis[i]," \n"[i==n]);
}
return 0;
}