POJ 2528 Mayor's posters 贴海报 线段树 区间更新
注意离散化!!!线段树的叶子结点代表的是一段!!!
给出下面两个简单的例子应该能体现普通离散化的缺陷:
1-10 1-4 5-10
1-10 1-4 6-10
普通离散化算出来的结果都会是2,但是第二组样例结果是3
如果相邻数字间距大于1的话,在其中加上任意一个数字,比如加成[1,2,3,6,7,10],然后再做线段树就好了.
线段树功能:update 成段更新,query 查询整个线段树
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define lson l, m, rt<<1 #define rson m+1, r, rt<<1|1 using namespace std; const int MAXN = 20010; int p[MAXN], mp[MAXN], pp[MAXN]; int pst[MAXN<<4], ans; bool flag[MAXN]; bool cmp(int A, int B) { return p[A] < p[B]; } void push_down(int rt) { if(pst[rt] == 0) return; pst[rt<<1] = pst[rt<<1|1] = pst[rt]; pst[rt] = 0; } void update(int L, int R, int c, int l, int r, int rt) { if(L <= l && r <= R) { pst[rt] = c; return; } push_down(rt); int m = (l + r) >> 1; if(m >= L) update(L, R, c, lson); if(m < R) update(L, R, c, rson); } void query(int l, int r, int rt) { if(pst[rt] > 0) //只有大于0才有海报 { if(!flag[pst[rt]]) ans++; flag[pst[rt]] = 1; return; } if(l == r) return; push_down(rt); int m = (l + r) >> 1; query(lson); query(rson); } int main() { // freopen("in.txt", "r", stdin); int T, n; scanf("%d", &T); while(T--) { scanf("%d", &n); for(int i=0; i<n; i++) { scanf("%d%d", &p[i<<1], &p[i<<1|1]); mp[i<<1] = i<<1; mp[i<<1|1] = i<<1|1; } sort(mp, mp+2*n, cmp); pp[mp[0]] = 1; int N = 1; for(int i=1; i<2*n; i++) //离散化 { if(p[mp[i]] == p[mp[i-1]]) pp[mp[i]] = N; else if(p[mp[i]] - p[mp[i-1]] > 1) //大于1的插一个数 { N += 2; pp[mp[i]] = N; } else pp[mp[i]] = ++N; } memset(pst, 0, sizeof(pst)); for(int i=0; i<n; i++) update(pp[i<<1], pp[i<<1|1], i+1, 1, N, 1); memset(flag, 0, sizeof(flag)); ans = 0; query(1, N, 1); printf("%d\n", ans); } return 0; }