题目链接: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4028
借鉴了一位大佬的博客: http://www.mamicode.com/info-detail-2277492.html
题意:给你以i为结尾的最长上升子序列的值,和每个值的区间范围求可行的a【i】
题解:差分约束,首先满足l[i]<=a[i]<=r[i],可以建一个虚拟节点n+1,那么有a[n+1]-a[i]<=-l[i],a[i]-a[n+1]<=r[i],同时当 (f[i]==f[j] && i
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <queue>
using namespace std;
const int maxn =100000+5;
const int inf =0x3f3f3f3f;
long long d[maxn];
int vis[maxn],head[maxn],last[maxn],k;
int T,n,l[maxn],r[maxn];
queue <int>q;
void init()
{
k=0;
memset(head,-1,sizeof(int)*(n+2));
memset(vis,0,sizeof(int)*(n+2));
memset(last,-1,sizeof(int)*(n+2));
while(!q.empty())
q.pop();
}
struct Edge
{
int v,w,next;
Edge(){};
Edge(int v1,int w1,int next1)
{
v=v1,w=w1,next=next1;
}
}e[maxn*5];
void add_edge(int u, int v, int w)
{
e[k]=Edge(v,w,head[u]);
head[u]=k++;
}
void spfa()
{
for(int i=0; i<=n; i++)
d[i]=1e18;
d[n+1]=0;
vis[n+1]=1;
q.push(n+1);
while(!q.empty())
{
int u=q.front();
q.pop();
vis[u]=0;
for(int i=head[u]; i!=-1; i=e[i].next)
{
int v=e[i].v;
int w=e[i].w;
if(d[v]>d[u]+w)
{
d[v]=d[u]+w;
if(!vis[v])
{
//printf("*");
q.push(v);
vis[v]=1;
}
}
}
}
return;
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
init();
int tmp;
for(int i=1; i<=n; i++)
{
scanf("%d",&tmp);
if(last[tmp]!=-1)
add_edge(last[tmp],i,0);
last[tmp]=i;
if(tmp!=1)
{
add_edge(i,last[tmp-1],-1);
}
}
for(int i=1; i<=n; i++)
{
scanf("%d %d",&l[i],&r[i]);
add_edge(i,n+1,-l[i]);
add_edge(n+1,i,r[i]);
}
spfa();
for(int i=1; i<=n; i++)
i==n? printf("%lld\n",d[i]):printf("%lld ",d[i]);
}
return 0;
}