种树-洛谷P1250(差分约束)

传送门

令前缀和为s[i],则⼀一个要求等价于 s[r] - s[l - 1] >= x。

题中还有别的要求,包括 s[i] - s[i - 1] <= 1 和 s[i] - s[i- 1] >= 0。

建一个超级原点s,把所有结点连到s(令s = n + 1)

差分约束系统规定的只是元素的相对关系

按照题意,相对关系不变时最后的答案尽可能小

因此最终答案应该是:dis[ n ] - min_dis

 

#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;

inline int read()
{
    int sum = 0,p = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-')
            p = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        (sum *= 10) += ch - '0';
        ch = getchar();
    }
    return sum * p;
}

const int maxn = 30005,maxm = 5005;
int n,m,s,cnt;
int dis[maxn],head[maxn];
bool vis[maxn];
struct edge
{
    int nxt,to,wei;
} e[maxn * 5];

void add(int x,int y,int z)
{
    e[++cnt].nxt = head[x];
    e[cnt].to = y;
    e[cnt].wei = z;
    head[x] = cnt;
}

void spfa(int x)
{
    queue<int> q;
    q.push(x);
    for(int i = 0; i <= n + 1; i ++)
        dis[i] = 1e9;
    dis[s] = 0;
    vis[s] = true;
    while(!q.empty())
    {
        int o = q.front();
        q.pop();
        vis[o] = false;
        for(int i = head[o]; i; i = e[i].nxt)
        {
            int v = e[i].to;
            if(dis[v] > dis[o] + e[i].wei)
            {
                dis[v] = dis[o]  + e[i].wei;
                if(!vis[v])
                {
                    q.push(v);
                    vis[v] = true;
                }
            }
        }
    }
}

int main()
{
    n = read(),m = read();
    s = n + 1;
    memset(head,-1,sizeof(head));
    for(int i = 0; i <= n; i++)
        add(s,i,0);
    int a,b,c;
    for(int i = 1; i <= m; i++)
    {
        a = read(),b = read(),c = read();
        add(b,a - 1,-c);
    }
    for(int i = 1; i <= n; i++)
    {
        add(i - 1,i,1);
        add(i,i - 1,0);
    }
    spfa(s);
    int ans = 1e9;
    for(int i=0; i<=n; i++)
         ans = min(ans, dis[i]);
    printf("%d",dis[n] - ans);
    return 0;
}

 

posted @ 2019-07-21 16:23  darrrr  阅读(138)  评论(0编辑  收藏  举报