poj—2528Mayor's posters-線段樹+區間離散化
阿新 • • 發佈:2019-02-14
題意:在牆上貼海報,海報可以互相覆蓋,問最後可以看見幾張海報
思路:線段樹+離散化
注意的是不能用普通的離散化,例如:
三張海報為:1~10 1~4 6~10
離散化時 X[ 1 ] = 1, X[ 2 ] = 4, X[ 3 ] = 6, X[ 4 ] = 10
第一張海報時:牆的1~4被染為1;
第二張海報時:牆的1~2被染為2,3~4仍為1;
第三張海報時:牆的3~4被染為3,1~2仍為2。
最終,第一張海報就顯示被完全覆蓋了,於是輸出2,但實際上明顯不是這樣,正確輸出為3。
ps:
POJ構造的數軸是這樣的 |___|___|___|___|___|___|___|___|
1 2 3 4 5 6 7 8
所以
輸入:1-10 1-4 5-10 得到的是2
輸入:1-10 1-4 6-10 得到的是3
為了解決這種缺陷,我們可以在排序後的陣列上加些處理,比如說
[1,2,6,10]
如果相鄰數字間距大於1的話,在其中加上任意一個數字,比如加成
[1,2,3,6,7,10],然後
再做線段樹就好了
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> using namespace std; const int w=11111; struct s{ int i,j,k; }a[15*w],b[w]; int x[w*3]; void build(int r,int i,int j) { a[r].i=i; a[r].j=j; a[r].k=0; if(i==j) { return ; } int k=(i+j)/2; build(r<<1,i,k); build(r<<1|1,k+1,j); } int visit(int y,int j) { int i=0,k; while(i<=j) { k=(i+j)/2; if(x[k]==y) return k; if(x[k]>y) j=k-1; else i=k+1; } } void pushdown(int r) { if(a[r].k) { a[r<<1].k=a[r<<1|1].k=1; } } int query(int r,int i,int j) { if(a[r].k) return 0; if(a[r].i>=i&&a[r].j<=j) { a[r].k=1; return 1; } pushdown(r); int y=0,k=(a[r].i+a[r].j)/2; if(j<=k) y=query(r<<1,i,j); else if(i>k) y=query(r<<1|1,i,j); else y=query(r<<1,i,j)|query(r<<1|1,i,j); //返回1表示還有空隙 if(a[r<<1].k&&a[r<<1|1].k) a[r].k=1; return y; } int main() { int n,m,i,j,t,T; scanf("%d",&T); while(T--) { scanf("%d",&n); t=0; for(i=0;i<n;i++) { scanf("%d%d",&b[i].i,&b[i].j); x[t++]=b[i].i,x[t++]=b[i].j; } sort(x,x+t); j=0; for(i=1;i<t;i++) { if(x[i]!=x[j]) x[++j]=x[i];//去重 } for(i=j;i>0;i--) { if(x[i]-x[i-1]!=1) x[++j]=x[i-1]+1; } sort(x,x+j+1); build(1,0,j); t=0; for(i=n-1;i>=0;i--) { if(query(1,visit(b[i].i,j),visit(b[i].j,j))) t++; } printf("%d\n",t); } return 0; }