1. 程式人生 > >【差分約束】POJ1201/LG SP116 Intervals

【差分約束】POJ1201/LG SP116 Intervals

題意翻譯

區間取數

題目描述

有n個區間,在區間[ai,bi]中至少取任意互不相同的ci個整數。求在滿足n個區間的情況下,至少要取多少個正整數。

輸入輸出格式

輸入格式

多組資料。

第一行的一個整數T表示資料個數。對於每組資料,第一行包含一個整數nn(11<=nn<=5000050000)表示區間數。以下nn行描述區間。輸入的第(i+1)行包含三個整數ai,bi,ci,由空格分開。其中0<=ai<=bi<=500001<=ci<=bi-ai+1。

輸出格式

對於每組資料,輸出一個對於n個區間[ai,bi] 至少取ci個不同整數的數的總個數。

輸入輸出樣例

輸入樣例#
11 5 3 7 3 8 10 3 6 8 1 1 3 1 10 11 1 輸出樣例#16
T

這道題呢又是一個差分約束

很明顯通過題意可以抽象出很多個b-(a-1)>=c

而且還有一點隱藏的東西1>=i-(i-1)>=0

轉換一下下就是i-(i-1)>=0,i-(i-1)>=-1

因為是大於,所以差分的時候要跑最長路

再次記憶一下,b-a>=a,建a到b的單向邊

然後堆疊spfa就能A了

程式碼

 1 #include<cstdio>
 2 #include<queue>
 3
#include<cstring> 4 #define N 50011 5 using namespace std; 6 struct star{int to,nxt,val;}edge[10*N]; 7 int dis[N],head[N],stk[N],mi=0x7f7f7f7f,ma=-1; 8 int cnt=1,n,a,b,c,top,t; 9 bool in[N]; 10 inline void add(int u,int v,int w) 11 { 12 edge[cnt].nxt=head[u]; 13 edge[cnt].to=v;
14 edge[cnt].val=w; 15 head[u]=cnt++; 16 } 17 int main() 18 { 19 scanf("%d",&t); 20 while(t--) 21 { 22 memset(head,-1,sizeof(head)); 23 memset(dis,~0x7f,sizeof(dis)); 24 cnt=1; 25 scanf("%d",&n); 26 for(int i=1;i<=n;i++) 27 { 28 scanf("%d%d%d",&a,&b,&c); 29 add(a-1,b,c); 30 mi=min(a-1,mi); 31 ma=max(ma,b); 32 } 33 for(int i=mi;i<=ma;i++) 34 add(i,i-1,-1),add(i-1,i,0); 35 stk[++top]=mi; 36 dis[mi]=0,in[mi]=1; 37 while(top) 38 { 39 int now=stk[top--];in[now]=0; 40 for(int i=head[now];i!=-1;i=edge[i].nxt) 41 { 42 int to=edge[i].to; 43 if(dis[to]<dis[now]+edge[i].val) 44 { 45 dis[to]=dis[now]+edge[i].val; 46 if(!in[to]) 47 {stk[++top]=to;in[to]=1;} 48 } 49 } 50 } 51 printf("%d\n",dis[ma]); 52 } 53 return 0; 54 }