poj2528 线段树+离散化

来源:互联网 发布:知乎俄罗斯航空发动机 编辑:程序博客网 时间:2024/05/19 23:25

不清楚为什么数组开小了是wa而不是re

这题其实主要在离散化的操作

离散化完成后 其实就是zoj1610染色覆盖一个题意了 希望大家在做这道题之间先把zoj1610做了

看了kuangbin的博客知道了离散的特殊之处

例子一:1-10 1-4 5-10

例子二:1-10 1-4 6-10

普通离散化后都变成了[1,4][1,2][3,4]
线段2覆盖了[1,2],线段3覆盖了[3,4],那么线段1是否被完全覆盖掉了呢?
例子一是完全被覆盖掉了,而例子二没有被覆盖

解决的办法则是对于距离大于1的两相邻点,中间再插入一个点。

具体实现看代码和注释吧

#include<algorithm>#include<iostream>#include<cstdlib>#include<cstring>#include<cstdio>#include<string>#include<stack>#include<queue>#include<cmath>#include<stack>#include<list>#include<map>#include<set>typedef long long ll;#define exp 1e-8#define llinf 1000000000000000000#define gi(x) scanf("%d",&x)#define gi2(x,y) scanf("%d%d",&x,&y)#define gll(x) scanf("%lld",&x)#define gll2(x,y) scanf("%lld%lld",&x,&y)#define gc(x) scanf("%c",&x)#define gc2(x,y) scanf("%c%c",&x,&y)#define up(i,x,y) for(i=x;i<=y;i++)#define down(i,x,y) for(i=x;i>=y;i--)#define mem(a,x) memset(a,x,sizeof(a))using namespace std;const int MAXN=20005;const int mod=1000000007;const int inf=0x3f3f3f3f;int num[MAXN<<4];//数组开小了 为什么会waint vis[MAXN];//vis[i]==1说明颜色i存在int a[MAXN<<4];//用于离散化int maxn=1;//最终更新成线段树的最大下标struct Node {int l;int r;}node[MAXN];//记录n个海报的l和rstruct Tree {int l,r;int color;int flag;}tree[MAXN<<4];//线段树void pushdown(int root)//这里跟zoj1610同理 {int temp=root<<1;tree[temp].color=tree[root].color;tree[temp+1].color=tree[root].color;tree[root].color=-1;}void build(int l,int r,int root){tree[root].l=l;tree[root].r=r;tree[root].flag=1;//这个点被用过tree[root].color=-1;if(l==r){maxn=max(maxn,root);//更新最大下标return ;}int mid=(l+r)/2;build(l,mid,root*2);build(mid+1,r,root*2+1);}void update(int l,int r,int root,int c){if(tree[root].color==c)//无需更新了{return ;}if(l>tree[root].r||r<tree[root].l)//更新区间和此节点存放的区间没有任何交集 直接return{return ;}if(tree[root].r<=r&&tree[root].l>=l) //此节点被包含在需要更新的区间中,此节点的color就更新为c{tree[root].color=c;return ;}if(tree[root].color!=-1){pushdown(root);}update(l, r, root*2, c);update(l,r,root*2+1,c);    }void getans(int n){int i;mem(num,-1);mem(vis,0);for(i=1;i<=maxn;i++){if(tree[i].flag==0)//这个点没被用过 进入下一次循环continue;if(tree[i].color!=-1)//没有颜色的无需处理了 因为num都初始化为-1了{if(tree[i].l==tree[i].r)//区间长度为1{num[tree[i].l]=tree[i].color;//用num数组在存i这个点的海报是哪一个}pushdown(i);}}int ans=0;for(i=1;i<=n;i++)//统计海报的种类个数{if(num[i]!=-1){int t=num[i];if(vis[t]==0){vis[t]=1;ans++;}}}printf("%d\n",ans);}int main(){int i,n;int T;scanf("%d",&T);while(T--){maxn=1;scanf("%d",&n);for(i=0;i<MAXN<<4;i++){tree[i].flag=0;//flag==0说明tree[i]没有被用过}int cnt=0;for(i=1;i<=n;i++){scanf("%d%d",&node[i].l,&node[i].r);a[cnt++]=node[i].l;a[cnt++]=node[i].r;}    sort(a,a+cnt);int s=unique(a, a+cnt)-a;//排序+去重cnt=s;int t=cnt;for(i=1;i<t;i++)//特殊的离散化的处理{if(a[i]-a[i-1]>1){a[cnt++]=a[i-1]+1;}}sort(a,a+cnt);//排序 build(1,cnt,1);//建树 我这里建树的区间范围是[1,cnt]for(i=1;i<=n;i++){int x=(lower_bound(a,a+cnt,node[i].l)-a)+1;//因为建树的范围是从1开始 所以要+1int y=(lower_bound(a,a+cnt,node[i].r)-a)+1;update(x,y,1,i);//更新颜色}getans(cnt);}return 0;}