题目大意:多位候选人要在墙上贴海报,海报可以相互重叠,问贴完了以后还有多少海报可以看见。
思路:经典的线段树问题,同时需要离散化坐标点。
#include <iostream> #include <algorithm> #include <stdio.h> #include <string.h> using namespace std; const int MAXN = 10000001;//节点数量 const int DISCRETE_MAXN = 10010*2;//离散之后节点数量 const int COLOR_NUM = 20001;//所染颜色数量 const int DEFAULT_COLOR = 0;//默认颜色 struct node{//线段树节点 int left, right;//区间左右坐标 int color; }; node tree[DISCRETE_MAXN*4]; bool visit[COLOR_NUM]; int l, n; node discreteTree[DISCRETE_MAXN*4];//离散点 bool discreteVisit[MAXN];//标志离散点 int discreteValue[DISCRETE_MAXN*4];//离散值 int discreteNum;//离散量 int resultValue[MAXN];//最终离散值 //离散化 //返回离散化后最大的值 int discrete() { int i = 1; scanf("%d", &n); for(i = 1 ; i <= n ; i++){ scanf("%d %d", &discreteTree[i].left, &discreteTree[i].right); if(!discreteVisit[discreteTree[i].left]){ discreteValue[discreteNum++] = discreteTree[i].left; discreteVisit[discreteTree[i].left] = true; } if( !discreteVisit[discreteTree[i].right] ){ discreteValue[discreteNum++] = discreteTree[i].right; discreteVisit[discreteTree[i].right] = true; } } sort(discreteValue, discreteValue+discreteNum); int j = 1; for( i = 0 ; i < discreteNum ; i++ ){ //离散化过程 discreteVisit[discreteValue[i]] = false; resultValue[discreteValue[i]] = j++; } return j-1; } //建树 //参数: 区间左边坐标, 区间右边坐标, 节点下标 void build(const int &left, const int &right, const int &nodeNum = 1) { tree[nodeNum].left = left; tree[nodeNum].right = right; tree[nodeNum].color = DEFAULT_COLOR; if (left == right)//终结条件, 区间剩下一个点的时候 return ; int mid = (left + right) >> 1;//求中点 build(left, mid, 2*nodeNum);//建左子树 build(mid+1, right, 2*nodeNum+1);//建右子树 } //建树的初始化函数 void init() { build(1, l);//默认总区间是[1, l] tree[1].color = 1;//先给总的区间上一种颜色 } //往线段树插入数据/修改数据 //参数: 区间左边坐标, 区间右边坐标, 修改的区间颜色, 节点下标 void insert(const int &left, const int &right, const int &color, const int &nodeNum = 1) { if (left == tree[nodeNum].left && right == tree[nodeNum].right){//如果区间刚刚好为要填充的区间, 修改区间的颜色值,终止 tree[nodeNum].color = color; return ; } if (DEFAULT_COLOR != tree[nodeNum].color){//区间已经染过颜色 tree[nodeNum*2].color = tree[nodeNum*2+1].color = tree[nodeNum].color;//左右区间记录原来区间的颜色 tree[nodeNum].color = DEFAULT_COLOR;//区间设置为未染色颜色 } int mid = (tree[nodeNum].left + tree[nodeNum].right) >> 1;//获取区间的中点 if (right <= mid){//修改区间全在当前的左半部分区间 insert(left, right, color, nodeNum*2);//去左子树修改颜色值 }else if (left > mid){//修改区间全在当前的右半部分区间 insert(left, right, color, nodeNum*2+1);//去右子树修改颜色值 }else{ insert(left, mid, color, nodeNum*2); insert(mid+1, right, color, nodeNum*2+1); } } //查询函数 //参数: 查询区间左坐标, 有坐标, 节点下标 //返回: 查询区间里面不同颜色的数量 int query(const int &left, const int &right, const int &nodeNum = 1) { int count = 0; if (tree[nodeNum].color != DEFAULT_COLOR) { if (visit[tree[nodeNum].color] == false) { count++; visit[tree[nodeNum].color] = true; } return count; } int mid = (tree[nodeNum].left + tree[nodeNum].right) >> 1; if (right <= mid){ count += query(left, right, nodeNum*2); }else if (left > mid){ count += query(left, right, nodeNum*2 + 1); }else { count += query(left, mid, nodeNum*2); count += query(mid+1, right, nodeNum*2 + 1); } return count; } int main() { int t, color; scanf("%d", &t); memset(discreteVisit, false, sizeof(discreteVisit)); while (t--) { l = 20010; init();//线段树初始化 color = 2; discreteNum = 0; memset(visit, false, sizeof(visit)); int maxX = discrete(); for (int i = 1; i <= n; ++i){ insert(resultValue[discreteTree[i].left], resultValue[discreteTree[i].right], color++); } printf("%d\n", query(1, maxX)); } return 0; }