题意:

有一个长度为n的隐藏的数列a,再给出一个数列f,f[i]是到i(包括自己)的最长递增数列的长度,给出每个数的范围,求出这个隐藏的数列a。

思路:

差分约束。

时,有,即,所以有i->j的权值为-1的边。

时,有,即,所以有j->i的权值为0的边。

那么范围如何处理呢?

假定有一个超级源点,对于每个范围[l,r],

,即,所以有i->0的权值为-l的边,

,所以有0->i的权值为r的边。

之后跑一下SPFA即可。

这里注意要用long long。

代码:

#define INF 0x3f3f3f3f3f3f3f3f
int pre[500010];
struct edge
{
    int to;
    int cost;
};
vector<edge>v[500010];
ll dis[500010];
bool vis[500010];
int cnt[500010];
int n,tp;
bool spfa()
{
    fill(dis,dis+1+n,INF);
    fill(vis,vis+1+n,false);
    fill(cnt,cnt+1+n,0);
    queue<int>q;q.push(0);
    vis[0]=true;dis[0]=0;cnt[0]++;
    while(!q.empty())
    {
        tp=q.front();vis[tp]=false;
        q.pop();
        for(int i=0;i<v[tp].size();i++)
        {
            edge &e=v[tp][i];
            if(dis[tp]+e.cost<dis[e.to])
            {
                dis[e.to]=dis[tp]+e.cost;
                if(!vis[e.to])
                {
                    q.push(e.to);
                    vis[e.to]=true;
                    cnt[e.to]++;
                    if(cnt[e.to]>n)return true;   //判断负环
                }
            }
        }
    }
    return false;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int x,l,r;
        scanf("%d",&n);
        for(int i=0;i<=n;i++)
        {
            pre[i]=0;
            v[i].clear();
        }
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&x);
            if(pre[x-1]!=0)
            {
                edge temp;
                temp.to=pre[x-1];temp.cost=-1;
                v[i].push_back(temp);
            }
            if(pre[x]!=0)
            {
                edge temp;
                temp.to=i;temp.cost=0;
                v[pre[x]].push_back(temp);
            }
            pre[x]=i;
        }
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&l,&r);
            edge temp;
            temp.to=0;temp.cost=-l;
            v[i].push_back(temp);
            temp.to=i;temp.cost=r;
            v[0].push_back(temp);
        }
        spfa();
        for(int i=1;i<n;i++)
            printf("%lld ",dis[i]);
        printf("%lld\n",dis[n]);
    }
    return 0;
}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!

ZOJ4027 DP+预处理 Previous
ZOJ4029 数学+预处理+二分 Next