種樹(一道簡單的差分約束系統)
阿新 • • 發佈:2019-02-03
【資料範圍】
對於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; }