1. 程式人生 > >種樹(一道簡單的差分約束系統)

種樹(一道簡單的差分約束系統)

【資料範圍】


對於30%的資料,0<n≤100,0<m≤100,ki=1;


對於50%的資料,0<n≤2,000,0<m≤5,000,0<ki≤100;


對於70%的資料,0<n≤50,000,0<m≤100,000,0<ki≤1,000;


對於100%的資料,0<n≤500,000,0<m≤500,000,0<ki≤5,000

用s陣列表示字首和,很容易列出不等式s[r[i]]-s[l[i]-1]>=c[i],和s[i]-s[i-1]<=k[i],還有一個比較容易忘記(我就忘了,然後炸飛)s[i]-s[i-1]>=0

看到這一串不等式,差分約束系統就很明顯了。移項,得到s[r[i]]>=s[l[i]-1]+c[i],s[i]>=s[i-1]+0,s[i-1]>=s[i]+(-k[i]),根據三角形不等式連變,l[i]-1到r[i]連一條權值為c[i]的邊(1<=i<=m),i-1到i連一條權值為0的邊(1<=i<=n),i到i-1連一條權值為-k[i]的邊(1<=i<=n)。

然後跑最長路SPFA。

附上程式碼

#include<iostream>  
#include<cstdio>  
#include<cmath>  
#include<algorithm>  
#include<cstdlib>  
#include<cstring>  
#include<queue>  
using namespace std;  
int n,m,vet[3000000],Next[3000000],head[1000000],en,b[1000000],s,t;  
bool vis[1000000];  
long long w[3000000],dis[1000000];  
queue<int> Q;  
void addedge(int u,int v,long long val){  
    en++;  
    vet[en]=v;  
    w[en]=val;  
    Next[en]=head[u];  
    head[u]=en;  
}  
int main(){  
    scanf("%d%d",&n,&m);  
    for(int i=1;i<=n;i++){  
        long long x;  
        scanf("%lld",&x);  
        addedge(i,i-1,-x);  
    }  
    for(int i=1;i<=m;i++){  
        long long z;  
        int x,y;  
        scanf("%d%d%lld",&x,&y,&z);  
        addedge(x-1,y,z);  
    }  
    for(int i=0;i<=n;i++)  
        addedge(n+1,i,0);  
    for(int i=1;i<=n;i++)
    addedge(i-1,i,0);//不要忘記
    s=n+1;  
    t=n;  
    vis[s]=true;  
    b[s]=1;  
    Q.push(s);  
    for(int i=0;i<=n;i++)  
        dis[i]=-1000000000;  
    while(!Q.empty()){  
        int u=Q.front();  
        Q.pop();  
        vis[u]=false;  
        for(int i=head[u];i;i=Next[i]){  
            int v=vet[i];  
            if(dis[u]+w[i]>dis[v]){  
                dis[v]=dis[u]+w[i];  
                b[v]++;  
                if(!vis[v]){  
                    Q.push(v);  
                    vis[v]=true;  
                }  
            }  
        }  
    }  
    printf("%lld\n",dis[t]);  
    return 0;  
}