ZOJ1610(區間覆蓋問題+線段樹)
阿新 • • 發佈:2018-12-09
區間覆蓋問題,參考POJ2528的解法。(以下簡稱POJ2528為參考題)
1.對於輸入資料的處理:輸入和參考題不同,輸入的是染色區間的端點,而參考題輸入的是一段區間的編號。所以對資料進行輸入的處理,處理方式為:[0,4]相當於對四段區間覆蓋(也可以說染色):【0,1】,【1,2】,【2,3】,【3,4】我們根據參考題的解法對區間進行編號處理:將右端點的值作為區間的編號,這樣我們的輸入就可以實現端點到區間的轉換。就可以根據參考題的解法來處理。
處理方式:輸入L,R後,將L++.
2. 使用ret陣列來儲存每種顏色出現的段數。
3.注意下推函式中,在下推完成後必須對當前結點的標記刪除!否則一個非常重要的影響是:線上段樹中考慮該節點,我們更新該節點區間下的染色時,該節點底層的染色會被該節點的顏色覆蓋!
4.我們將tree[]陣列的初始值考慮成一種顏色-1,遍歷到底層時不能返回(將temp更新為-1)因為按照題意,不相鄰的兩端區間的染色(中間即使沒有其他顏色)也算作一種顏色的兩段。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<string> using namespace std; const int maxn=8000+10; int tree[maxn<<4]; int ret[maxn]; int n,L,R,C; void pushdown(int rt) { tree[rt<<1]=tree[rt<<1|1]=tree[rt]; tree[rt]=-1; } void update(int l,int r,int rt) { if(L<=l&&r<=R) { tree[rt]=C; return; } int m=(l+r)>>1; if(tree[rt]!=-1) pushdown(rt); if(L<=m) update(l,m,rt<<1); if(m<R) update(m+1,r,rt<<1|1); } int temp;//記錄上一個區域的顏色 void query(int l,int r,int rt) { if(tree[rt]!=-1) { if(temp!=tree[rt]) ret[tree[rt]]++; temp=tree[rt]; //printf("運次到底層\n"); return; } if(l==r) { temp=-1; return; } int m=(l+r)>>1; query(l,m,rt<<1); query(m+1,r,rt<<1|1); } int main() { while(~scanf("%d",&n)) { memset(tree,-1,sizeof(tree)); memset(ret,0,sizeof(ret)); for(int i=0; i<n; ++i) { scanf("%d%d%d",&L,&R,&C); L++; update(1,8001,1); } temp=-1; query(1,8001,1); for(int i=0; i<=8001; ++i) if(ret[i]) printf("%d %d\n",i,ret[i]); puts(""); } return 0; }