类型:给出一些形如a−b<=k的不等式(或a−b>=k或a−b<k或a−b>k等),问是否有解【是否有负环】或求差的极值【最短/长路径】。
例子:b−a<=k1,c−b<=k2,c−a<=k3。将a,b,c转换为节点;k1,k2,k3转换为边权;减数指向被减数,形成一个有向图:
由题可得(b−a) + (c−b) <= k1+k2,c−a<=k1+k2。比较k1+k2与k3,其中较小者就是c−a的最大值。
由此我们可以得知求差的最大值,即上限被约束,此时我们拿最小的限制,也就是跑最短路;反之,求差的最小值,下限被约束,我们跑最长路。
跑最短路时:d[v]<=d[u]+w
跑最长路时:d[v]>=d[u]+w
路径中可能会存在负边,用SPFA跑。判断负环,最短最长路均可
题意:
[a,b]区间内有>=c个数,计算集合里至少多个元素
思路:
因为数据范围 0 <= ai <= bi <= 50000,可以设s[i]为i之前元素个数【不含i】,将题意转化为差分约束,s[b+1]-s[a]>=c,防止a-1出界。
求s[end]>=?,求下限,求最长路,注意数组初始化和d数组更新条件
解决不连通有两个方法:
1. 新增特殊点或在区间内以1为单位连通
2.所有点全部入队,并标记
1 #include <queue> 2 #include <cstdio> 3 #include <cstring> 4 #include <iostream> 5 #include <algorithm> 6 using namespace std; 7 8 const int N=50005; 9 int n,cnt; 10 const int INF=0x3f3f3f3f; 11 int head[N],d[N]; 12 bool vis[N]; 13 14 struct e{ 15 int to,next,w; 16 }edge[N<<2]; // 有反向边 17 18 void add(int u,int v,int w){ 19 edge[cnt].w=w;edge[cnt].to=v;edge[cnt].next=head[u];head[u]=cnt++; 20 } 21 22 void init(){ 23 cnt=0; 24 memset(head,-1,sizeof(head)); 25 } 26 27 void SPFA(int s) 28 { 29 memset(d,-INF,sizeof(d)); 30 memset(vis,0, sizeof(vis)); 31 queue<int> q; 32 q.push(s); 33 d[s]=0; 34 vis[s]=1; 35 while(q.size()) 36 { 37 int u = q.front();q.pop(); 38 vis[u]=0; 39 for(int i=head[u];i!=-1;i=edge[i].next) 40 { 41 int v=edge[i].to; 42 int w=edge[i].w; 43 if(d[v]<d[u]+w) 44 { 45 d[v]=d[u]+w; 46 if(!vis[v]) 47 { 48 q.push(v); 49 vis[v]=1; 50 } 51 } 52 } 53 } 54 } 55 56 57 int main(){ 58 while(scanf("%d",&n)!=EOF) { 59 init(); 60 int st = INF, ed = -INF; 61 for (int i = 1; i <= n; i++) { 62 int a, b, c; 63 cin >> a >> b >> c; 64 add(a, b + 1, c); 65 st = min(st, a); 66 ed = max(ed, b + 1); 67 } 68 for (int i = st; i < ed; i++) { 69 add(i, i + 1, 0); 70 add(i + 1, i, -1); 71 } 72 SPFA(st); 73 cout << d[ed] << endl; 74 } 75 return 0; 76 }