poj 2528(線段樹+離散化)
阿新 • • 發佈:2019-02-17
如圖,貼海報,後面的海報可以貼在前面的海報的上面,按給定的順序在區間為(l,r)的位置去貼海報,問最後可以在表面看見的海報有多少張
給定的區間範圍很大,為1 <= li <= ri <= 10000000
靜態的話,直接用線段樹進行區間更新,需要1000000個葉子節點,還沒TLE就已經MLE了
但是海報的數目1 <= n <= 10000,所以進行離散化
例如
1 4,2 6,9,12三張海報
1,2,4,6,9,12 普通線段樹需要12個葉節點
離散化思想
seg[0]=1,seg[1]=2,seg[2]=4,seg[3],seg[4]=6,seg[5]=9,seg[6]=12
此時 線段區間由1—12壓縮到了0—6,
本題特殊的地方在於,如果區間序列為[1,10],[1,4],[9,10]
那麼
i 0 1 2 3
seg 1 4 9 10
如圖,[0,0]和[1,1]記錄了第二張海報,[2,2]和[3,3]記錄了第三章海報
計算答案為2,但實際答案為3,第一張海報還是可以看見的
解決方法在4後面插入5,變成
i 0 1 2 3 4
seg 1 4 5 9 10
!!這題陣列開的奇大無比,試了好多次一直REsegTree[maxn*16+5];
程式碼如下,
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; const int maxn=11111; struct node1 { int l,r,id; }segTree[maxn*16+5]; struct node2 { int l,r; }poster[maxn+5]; bool vis[10010]; int seg[4*maxn+5]; int ans; void push_down(int i) { if(segTree[i].id!=-1){ segTree[i<<1].id=segTree[i].id; segTree[(i<<1)|1].id=segTree[i].id; segTree[i].id=-1; } } void build(int i,int l,int r) { segTree[i].l=l; segTree[i].r=r; segTree[i].id=-1; if(l==r)return; int mid=(l+r)/2; build(i<<1,l,mid); build((i<<1)|1,mid+1,r); } void update(int i,int l,int r,int id) { if(segTree[i].l==l&&segTree[i].r==r){ segTree[i].id=id; return; } push_down(i); int mid=(segTree[i].l+segTree[i].r)/2; if(r<=mid)update(i<<1,l,r,id); else if(mid<l)update((i<<1)|1,l,r,id); else{ update(i<<1,l,mid,id); update((i<<1)|1,mid+1,r,id); } } void query(int i,int l,int r) { if(segTree[i].id!=-1){//不用判斷區間,之間檢查染色情況 if(!vis[segTree[i].id]){ vis[segTree[i].id]=true; ans++; } segTree[i].id=-1; return; } if(l==r)return; push_down(i); int mid=(segTree[i].l+segTree[i].r)/2; if(r<=mid)query(i<<1,l,r); else if(l>mid)return query((i<<1)|1,l,r); else { query(i<<1,l,mid); query((i<<1)|1,mid+1,r); } } int BSearch(int low,int high,int num) { int mid; while(low<=high){ mid=(low+high)/2; if(num==seg[mid])return mid; else if(seg[mid]>num)high=mid-1; else low=mid+1; } return low; } int main() { //freopen("in.txt","r",stdin); int c,n,cnt,m; scanf("%d",&c); while(c--){ memset(vis,0,sizeof(vis)); cnt=0; scanf("%d",&n); for(int i=0;i<n;i++){ scanf("%d%d",&poster[i].l,&poster[i].r); seg[cnt++]=poster[i].l;seg[cnt++]=poster[i].r; } sort(seg,seg+cnt); m=1; for(int i=1;i<cnt;i++) if(seg[i]!=seg[i-1])seg[m++]=seg[i]; for(int i=m-1;i>=1;i--) if(seg[i]-seg[i-1]>1)seg[m++]=seg[i-1]+1; sort(seg,seg+m); build(1,1,m); for(int i=0;i<n;i++){ int l=BSearch(0,m-1,poster[i].l);//利用二分查詢離散處理後的位置 int r=BSearch(0,m-1,poster[i].r); update(1,l+1,r+1,i); } ans=0; query(1,1,m); printf("%d\n",ans); } return 0; }