//线段树的染色类型题目 //这题通过逆序修改线段树可以简单的实现,这是一种比较巧妙地做法 //也可以通过记录左颜色和右颜色来维护线段树实现 //下面的代码是通过逆序覆盖来实现的,逆序覆盖,即将最后一次贴上去的海报优先处理 //这样的话可以省去很多按顺序插入处理步骤,但是无法实现动态询问 //在离散化的时候我一开始使用MAP来实现,结果800MS,差点爆掉,实践证明MAP的查询速度是很慢的,还不如写个二分搞定 //但下面的代码严格来说是错误的,离散化有问题,不过数据太弱,还是可以AC的 #include<iostream> #include<algorithm> #include<vector> #define MAX 10005 using namespace std; struct seg { int l,r,color,cover; }segTree[8 * MAX];//4 是线段树特征,2是10000次边最坏有20000个不同边界,所以要*8 struct Extent//区间的结构体 { int x,y; }extent[MAX]; bool vis[2 * MAX]; int M[2 * MAX]; int ans,N; void buildTree(int fa,int l,int r)//建树 { segTree[fa].l = l; segTree[fa].r = r; segTree[fa].color = segTree[fa].cover = 0; if(l == r) return; int mid = (segTree[fa].l + segTree[fa].r) >> 1; if(r <= mid) buildTree(2*fa,l,r); else if(l > mid) buildTree(2*fa+1,l,r); else { buildTree(2*fa,l,mid); buildTree(2*fa+1,mid+1,r); } } int getIndex(int data)//通过二分查找返回离散后的数组下标 { int mid,x = 1,y = N+1; while(x < y) { mid = x + (y - x) / 2;//确保分界点总是靠近区间起点 if(M[mid] == data) return mid; else if(M[mid] > data) y = mid; else x = mid + 1; } return -1; } void insert(int fa,int l,int r,int color) { if(segTree[fa].cover > 0) return;//逆序覆盖,所以如果该区间已被覆盖过了,就直接返回即可,因为前面的覆盖对结果没有影响 if(l == segTree[fa].l && r == segTree[fa].r) { if(segTree[fa].cover == 0) { segTree[fa].color = color;//染色 segTree[fa].cover = 1; if(!vis[color])//如果这种颜色没出现过 { ++ans; vis[color] = 1; } } return; } int mid = (segTree[fa].l + segTree[fa].r) >> 1; if(r <= mid) insert(2*fa,l,r,color); else if(l > mid) insert(2*fa+1,l,r,color); else { insert(2*fa,l,mid,color); insert(2*fa+1,mid+1,r,color); } if(segTree[2*fa].cover > 0 && segTree[2*fa+1].cover > 0)//通过回溯跟结点顺便维护区间的覆盖情况 segTree[fa].cover = 1; } int main() { //freopen("in.txt","r",stdin); int t,n,x,y; scanf("%d",&t); while(t--) { N = 0; int color = 0; scanf("%d",&n); vector<int> v; memset(vis,0,sizeof(vis)); ans = 0; for(int i = 0;i < n;++i) { scanf("%d%d",&extent[i].x,&extent[i].y); v.push_back(extent[i].x); v.push_back(extent[i].y); } sort(v.begin(),v.end()); //离散化过程 M[++N] = v[0]; for(int i = 1;i < v.size();++i) if(v[i] != v[i-1]) M[++N] = v[i]; buildTree(1,1,N); for(int i = n - 1;i >= 0;--i) { x = getIndex(extent[i].x); y = getIndex(extent[i].y); insert(1,x,y,++color);//对每条边插入不同的颜色 } printf("%d/n",ans); } return 0; }