小记:这题真TMD烦啊,我一个建树出现了一点小问题,就是没有建立起叶子节点像(1,1) (2,2)等这样的点,导致了答案一直错,连样例都过不了,但是我又想不通哪里错了
QAQ
思路:首先hash离散化,有用线段树做矩形交面积等题的应该会有用到的时候,离散化就是将原本离的很开的点,变成连续的点,这样建树就不会MLE了。
例如原本是 2 10 100 1000,离散化一下就变成
1 2 3 4
就这样。
离散化的原因就是因为题目的数据,一个1千万,一个1万,必须离散化
然后线段树就是为每一个海报插入线段树,然后标记所染的色,之前有的也覆盖掉。
线段树节点加一个颜色标记,表示这一段是什么颜色,
在这里-1表示多色,0表示无色,大于0表示单色
循环的插入线段树里,对每一段依次染色,完成染色之后就是计算结果了
递归求解,如果某一段是单色那么就看这个颜色是否被标记了,没有被标记那么就标记,然后答案就+1,否则就继续往下递归,无色的就不要递归了。
代码:
#include <iostream> #include <stdio.h> #include <string.h> #include <math.h> #include <stdlib.h> #include <map> #include <set> #include <vector> #include <stack> #include <queue> #include <algorithm> using namespace std; #define mst(a,b) memset(a,b,sizeof(a)) #define REP(a,b,c) for(int a = b; a < c; ++a) #define eps 10e-8 const int MAX_ = 10010; const int N = 10000010; const int INF = 0x7fffffff; struct node{ int l, r; int col; }tree[MAX_*8]; int ans; int a[MAX_], b[MAX_]; int x[MAX_*2]; int hash[N]; bool vis[MAX_]; void build(int l, int r, int k) { int mid = l + (r-l)/2; tree[k].l = l; tree[k].r = r; tree[k].col = 0; if(l == r){ return ; } build(l, mid, k<<1); build(mid+1, r, (k<<1)|1); } void insert(int col, int l, int r, int k) { if(l > tree[k].r || r < tree[k].l){return ;} if(l <= tree[k].l && r >= tree[k].r){ tree[k].col = col; return ; } if(tree[k].col >= 0){ tree[k<<1].col = tree[(k<<1)|1].col = tree[k].col; tree[k].col = -1; } insert(col, l, r, k<<1); insert(col, l, r, (k<<1)|1); } void query(int k) { if(tree[k].col == 0)return ; if(tree[k].col > 0){ if(!vis[tree[k].col]){ vis[tree[k].col] = 1; ans++; } return ; } if(tree[k].col == -1){ query(k<<1); query(2*k+1); } return; } int main(){ int n, m, cnt, T; scanf("%d", &T); while(T-- && scanf("%d", &n)){ cnt = 0; ans = 0; mst(vis, 0); REP(i, 0, n){ scanf("%d%d", &a[i], &b[i]); x[cnt++] = a[i]; x[cnt++] = b[i]; } sort(x, x+cnt); cnt = unique(x, x+cnt) - x; m = 0; REP(i, 0, cnt){ hash[x[i]] = ++m; } build(1, m, 1); REP(i, 0, n){ insert(i+1, hash[a[i]], hash[b[i]], 1); } query(1); printf("%d\n", ans); } return 0; }