POJ 2374
挺水的一道线段树+DP题。可以从底往上添加线段,每添加线段之前查询端点所被覆盖的区间线段。再从最顶往下DP,每次从端点出发,递推覆盖该端点的区间线段的两端的值即可。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 #include <cctype> 5 #include <algorithm> 6 #define LL __int64 7 using namespace std; 8 9 const int N= 200050; 10 const int SN=50010; 11 const int inf=(1<<30); 12 int mark[N*4]; 13 int n,s; 14 int dp[SN][2]; 15 struct Seg{ 16 int l,r; 17 int li,ri; 18 }seg[SN]; 19 20 void PushDown(int rt){ 21 if(mark[rt]!=-1){ 22 mark[rt<<1]=mark[rt<<1|1]=mark[rt]; 23 mark[rt]=-1; 24 } 25 } 26 27 void update(int rt,int L,int R,int l,int r,int d){ 28 if(L<=l&&r<=R){ 29 mark[rt]=d; 30 return ; 31 } 32 PushDown(rt); 33 int m=(l+r)>>1; 34 if(L<=m)update(rt<<1,L,R,l,m,d); 35 if(m<R)update(rt<<1|1,L,R,m+1,r,d); 36 } 37 38 int query(int rt,int index,int l,int r){ 39 if(mark[rt]!=-1){ 40 return mark[rt]; 41 } 42 int m=(l+r)>>1; 43 if(index<=m) return query(rt<<1,index,l,m); 44 else return query(rt<<1|1,index,m+1,r); 45 } 46 47 int main(){ 48 while(scanf("%d%d",&n,&s)!=EOF){ 49 int mm=N,mc=-N; 50 memset(mark,-1,sizeof(mark)); 51 for(int i=n-1;i>=0;i--){ 52 scanf("%d%d",&seg[i].l,&seg[i].r); 53 mm=min(seg[i].l,mm); 54 mc=max(seg[i].r,mc); 55 dp[i][0]=dp[i][1]=inf; 56 } 57 seg[n].l=mm; seg[n].r=mc; 58 mm=abs(mm); 59 dp[n][0]=dp[n][1]=inf; 60 mm++; 61 update(1,1,seg[n].r+mm,1,mc+mm,n); 62 for(int i=n-1;i>=0;i--){ 63 seg[i].li=query(1,seg[i].l+mm,1,mc+mm); 64 seg[i].ri=query(1,seg[i].r+mm,1,mc+mm); 65 update(1,seg[i].l+mm,seg[i].r+mm,1,mm+mc,i); 66 } 67 dp[0][0]=abs(seg[0].l-s),dp[0][1]=abs(seg[0].r-s); 68 int ans=inf; 69 int li,ri; 70 for(int i=0;i<n;i++){ 71 li=seg[i].li; ri=seg[i].ri; 72 if(li==n){ 73 ans=min(ans,dp[i][0]+abs(seg[i].l-0)); 74 } 75 if(ri==n){ 76 ans=min(ans,dp[i][1]+abs(seg[i].r-0)); 77 } 78 dp[li][0]=min(dp[li][0],dp[i][0]+abs(seg[li].l-seg[i].l)); 79 dp[li][1]=min(dp[li][1],dp[i][0]+abs(seg[li].r-seg[i].l)); 80 dp[ri][0]=min(dp[ri][0],dp[i][1]+abs(seg[ri].l-seg[i].r)); 81 dp[ri][1]=min(dp[ri][1],dp[i][1]+abs(seg[ri].r-seg[i].r)); 82 } 83 printf("%d\n",ans); 84 } 85 return 0; 86 }