題目:給出一些牆,水從高往低流,每次只能到達一面牆,選擇一個路徑,使得路徑上的流量的最小值最大。 http://codeforces.com/problemset/problem/269/D 首先主要的是題意的理解問題。 像上圖這種情況的話,1是可以流向2的,1也是可以流向3的。 我開始的理解是1不能流向2,因為中間有3的阻擋,其實只是看公共部分的。 像這種情況1是不能流向2的,因為1和2的公共部分有3的阻擋。 理解這點之後,便好辦了。 按高度排序之後,將所有的坐標離散化。 按高度將線段插入到線段樹中,線段樹中維護這個區間最高的一條線段的標號,也就是標號的最大值。 對於線段3進行一次查詢之後,發現這段區間最後一次覆蓋的應該是線段2,但是線段3並非完全覆蓋於線段2的。 便可以繼續查詢綠色部分。 像左圖,查詢結果應該是線段1,所以3 是可以流向2,也是可以流向1的,這裡用dp做一次最優解就行了。 但是注意上面右圖的情況,查詢綠色部分,得到線段1,但是線段1的右端超過了綠色的右端,根據我們之前的查詢知道,綠色右端已經被2覆蓋,所以這時候要對兩端作一個標記,標明不能超過端點 [cpp] #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define test puts("OK"); #define inf 1000000000 #define lson (step<<1) #define rson (step<<1|1) using namespace std; const int N=100005; struct Wall{ int h,l,r; Wall(){} Wall(int _h,int _l,int _r):h(_h),l(_l),r(_r){} bool operator<(const Wall w)const{ return h<w.h; } }wall[N]; struct Seg_Tree{ int left,right; int val,all; }L[N<<3]; int n,t; int x[N<<1],cnt; //離散化 int dp[N]={0}; void Bulid(int step,int l,int r){ L[step].left=l; L[step].right=r; L[step].val=L[step].all=-1; if(l==r) return ; int m=(l+r)>>1; Bulid(lson,l,m); Bulid(rson,m+1,r); } void Push_Down(int step){ if(L[step].all!=-1){ L[lson].all=L[rson].all=L[step].all; L[lson].val=L[rson].val=L[step].all; L[step].all=-1; } } void Push_Up(int step){ L[step].val=max(L[lson].val,L[rson].val); } void Update(int step,int l,int r,int id){ if(L[step].left==l&&L[step].right==r){ L[step].val=L[step].all=id; return ; } Push_Down(step); int m=(L[step].left+L[step].right)>>1; if(r<=m) Update(lson,l,r,id); else if(l>m) Update(rson,l,r,id); else{ Update(lson,l,m,id); Update(rson,m+1,r,id); } Push_Up(step); } int Query(int step,int l,int r){ if(L[step].left==l&&L[step].right==r) return L[step].val; int m=(L[step].left+L[step].right)>>1; Push_Down(step); if(r<=m) return Query(lson,l,r); else if(l>m) return Query(rson,l,r); else return max(Query(lson,l,m),Query(rson,m+1,r)); } void slove(int l,int r,int who,int can_l,int can_r){ if(l>r) return ; int id=Query(1,l,r); if(id==-1){ Update(1,l,r,who); dp[who]=x[r+1]-x[l]; return ; } int pre_l=wall[id].l,pre_r=wall[id].r; if((pre_l>=l||can_l)&&(pre_r<=r||can_r)){ dp[who]=max(dp[who],min(dp[id],x[min(pre_r,r)+1]-x[max(pre_l,l)])); } if(l<pre_l) slove(l,pre_l-1,who,can_l,0); if(r>pre_r) slove(pre_r+1,r,who,0,can_r); } int main(){ scanf("%d%d",&n,&t); for(int i=0;i<n;i++){ int h,l,r; scanf("%d%d%d",&h,&l,&r); wall[i]=Wall(h,l,r); x[i*2]=l;x[i*2+1]=r; } x[n*2]=-inf;x[n*2+1]=inf; sort(x,x+2*n+2); cnt=unique(x,x+2*n+2)-x; wall[n++]=Wall(0,-inf,inf); wall[n++]=Wall(t,-inf,inf); sort(wall,wall+n); for(int i=0;i<n;i++){ wall[i].l=lower_bound(x,x+cnt,wall[i].l)-x; wall[i].r=lower_bound(x,x+cnt,wall[i].r)-x-1; } Bulid(1,0,cnt-1); for(int i=0;i<n;i++){ int l=wall[i].l,r=wall[i].r; slove(l,r,i,1,1); Update(1,l,r,i); } printf("%d\n",dp[n-1]); return 0; } #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define test puts("OK"); #define inf 1000000000 #define lson (step<<1) #define rson (step<<1|1) using namespace std; const int N=100005; struct Wall{ int h,l,r; Wall(){} Wall(int _h,int _l,int _r):h(_h),l(_l),r(_r){} bool operator<(const Wall w)const{ return h<w.h; } }wall[N]; struct Seg_Tree{ int left,right; int val,all; }L[N<<3]; int n,t; int x[N<<1],cnt; //離散化 int dp[N]={0}; void Bulid(int step,int l,int r){ L[step].left=l; L[step].right=r; L[step].val=L[step].all=-1; if(l==r) return ; int m=(l+r)>>1; Bulid(lson,l,m); Bulid(rson,m+1,r); } void Push_Down(int step){ if(L[step].all!=-1){ L[lson].all=L[rson].all=L[step].all; L[lson].val=L[rson].val=L[step].all; L[step].all=-1; } } void Push_Up(int step){ L[step].val=max(L[lson].val,L[rson].val); } void Update(int step,int l,int r,int id){ if(L[step].left==l&&L[step].right==r){ L[step].val=L[step].all=id; return ; } Push_Down(step); int m=(L[step].left+L[step].right)>>1; if(r<=m) Update(lson,l,r,id); else if(l>m) Update(rson,l,r,id); else{ Update(lson,l,m,id); Update(rson,m+1,r,id); } Push_Up(step); } int Query(int step,int l,int r){ if(L[step].left==l&&L[step].right==r) return L[step].val; int m=(L[step].left+L[step].right)>>1; Push_Down(step); if(r<=m) return Query(lson,l,r); else if(l>m) return Query(rson,l,r); else return max(Query(lson,l,m),Query(rson,m+1,r)); } void slove(int l,int r,int who,int can_l,int can_r){ if(l>r) return ; int id=Query(1,l,r); if(id==-1){ Update(1,l,r,who); dp[who]=x[r+1]-x[l]; return ; } int pre_l=wall[id].l,pre_r=wall[id].r; if((pre_l>=l||can_l)&&(pre_r<=r||can_r)){ dp[who]=max(dp[who],min(dp[id],x[min(pre_r,r)+1]-x[max(pre_l,l)])); } if(l<pre_l) slove(l,pre_l-1,who,can_l,0); if(r>pre_r) slove(pre_r+1,r,who,0,can_r); } int main(){ scanf("%d%d",&n,&t); for(int i=0;i<n;i++){ int h,l,r; scanf("%d%d%d",&h,&l,&r); wall[i]=Wall(h,l,r); x[i*2]=l;x[i*2+1]=r; } x[n*2]=-inf;x[n*2+1]=inf; sort(x,x+2*n+2); cnt=unique(x,x+2*n+2)-x; wall[n++]=Wall(0,-inf,inf); wall[n++]=Wall(t,-inf,inf); sort(wall,wall+n); for(int i=0;i<n;i++){ wall[i].l=lower_bound(x,x+cnt,wall[i].l)-x; wall[i].r=lower_bound(x,x+cnt,wall[i].r)-x-1; } Bulid(1,0,cnt-1); for(int i=0;i<n;i++){ int l=wall[i].l,r=wall[i].r; slove(l,r,i,1,1); Update(1,l,r,i); } printf("%d\n",dp[n-1]); return 0; }