• kb-07专题线段树-04--离散化;


     1   /*
      2    poj2528
      3   线段树 好题,用到了离散化,二分定位,特殊的区间查寻方式;在下面的代码注释中有详细的解释;
      4  */
      5 #include<iostream>
      6 #include<cstdio>
      7 #include<cstring>
      8 #include<algorithm>
      9 
     10 using namespace std;
     11 typedef struct
     12 {
     13     int l,r;
     14     int cnt;//记录该段有几张海报;
     15     int num;//记录该段下面是哪一张海报,0表示没有还海报或海报不唯一;
     16 }Node;
     17 int a[400010][2],n,dot[400010]={0},cou[400010]={0};
     18 Node tr[800010];
     19 void build(int rt,int l,int r)
     20 {
     21     tr[rt].l=l;
     22     tr[rt].r=r;
     23     tr[rt].cnt=0;
     24     tr[rt].num=0;
     25     if(l==r)
     26         return ;
     27     int mid=(l+r)/2;
     28     build(rt<<1,l,mid);
     29     build((rt<<1)|1,mid+1,r);
     30 }
     31 void Pushdown(int rt)
     32 {
     33     tr[rt<<1].cnt=1;
     34     tr[rt<<1|1].cnt=1;
     35     tr[rt<<1].num=tr[rt].num;
     36     tr[rt<<1|1].num=tr[rt].num;
     37     tr[rt].cnt=2;
     38     tr[rt].num=0;
     39 }
     40 void Update(int rt,int l,int r,int x)
     41 {
     42     if(tr[rt].l==l&&tr[rt].r==r)
     43     {
     44         tr[rt].cnt=1;
     45         tr[rt].num=x;
     46         return;
     47     }
     48     if(tr[rt].cnt==1)//当只有一张海报在这个区间的时候才需要pushdown所以可以判断一下;也可以写在pushdown函数里面,我觉得写在外面比较块;
     49         Pushdown(rt);
     50     if(l<=tr[rt<<1].r)
     51     {
     52         if(r<=tr[rt<<1].r)
     53             Update(rt<<1,l,r,x);
     54         else
     55             Update(rt<<1,l,tr[rt<<1].r,x);
     56     }
     57     if(r>=tr[rt<<1|1].l)
     58     {
     59         if(l>=tr[rt<<1|1].l)
     60             Update(rt<<1|1,l,r,x);
     61         else
     62             Update(rt<<1|1,tr[rt<<1|1].l,r,x);
     63     }
     64     if(tr[rt<<1].num==tr[rt<<1|1].num&&tr[rt<<1].cnt==1&&tr[rt<<1|1].cnt==1)//这以下是pushup的操作,写在这里了;
     65     {
     66         tr[rt].cnt=1;
     67         tr[rt].num=tr[rt<<1].num;
     68     }
     69     else 
     70         tr[rt].cnt=2;
     71 }
     72 /*
     73    查询操作比较有趣,因为是查寻区间的海报种类,一个海报可能是首尾可见而中间不可见,所以没办法直接查得,
     74     所以在树的结点上记录的是海报的编号,这样就可以用一个辅助的数组记录哪一个在此次查询中出现过;、
     75     所以每次查询要全区间查询,然后再扫一遍数组;
     76     、每次扫到区间内容一质的时候就不用再扫了;
     77   */
     78 void Query(int rt)
     79 {
     80     if(tr[rt].cnt==1)
     81     {
     82         cou[tr[rt].num]=1;
     83         return ;
     84     }
     85     if(tr[rt].l==tr[rt].r)
     86         return ;
     87     if(tr[rt].cnt==0)
     88         return ;
     89     Query(rt<<1);
     90     Query(rt<<1|1);
     91 }
     92 int Erfen(int l,int r,int x)//用来确定该点在线段上的位置(离散后的位置);
     93 {
     94     while(l<=r)
     95     {
     96         int mid=(l+r)/2;
     97         if(x<dot[mid])
     98             r=mid-1;
     99         else
    100             l=mid+1;
    101     }
    102     return r;
    103 }
    104 int main()
    105 {
    106     int T;
    107     scanf("%d",&T);
    108     while(T--)
    109     {
    110         memset(dot,0,sizeof(dot));
    111         scanf("%d",&n);
    112         int z=0;
    113         for(int i=0;i<n;i++)
    114         {
    115             scanf("%d%d",&a[i][0],&a[i][1]);
    116             dot[z++]=a[i][0];
    117             dot[z++]=a[i][1];
    118         }
    119         sort(dot,dot+z);//将输入的数据排序后是离散化;因为数据范围比较大,因为只和区间有关,与区间内部的点没有关系,所以只要区间首尾就好;
    120         int t=1;
    121         for(int i=1;i<z;i++)
    122         {
    123             if(dot[i]!=dot[i-1])
    124                 dot[t++]=dot[i];
    125         }
    126         for(int i=t-1;i>0;i--)
    127         {
    128             if(dot[i]-dot[i-1]>1)
    129                 dot[t++]=dot[i-1]+1;
    130         }
    131         sort(dot,dot+t);
    132         for(int i=t;i>0;i--)
    133             dot[i]=dot[i-1];
    134         memset(tr,0,sizeof(tr));
    135         build(1,1,t+5);
    136         for(int i=1;i<=n;i++)
    137         {
    138             int temp1=Erfen(1,t,a[i-1][0]);
    139             int temp2=Erfen(1,t,a[i-1][1]);
    140             Update(1,temp1,temp2,i);
    141         }
    142         memset(cou,0,sizeof(cou));
    143         Query(1);
    144         int ans=0;
    145         for(int i=1;i<=n;i++)
    146             if(cou[i]==1)
    147                 ans++;
    148         printf("%d
    ",ans);
    149     }
    150     return 0;
    151  }
  • 相关阅读:
    错删表空间的恢复步骤
    如何使用PL/SQL进行远程数据库连接
    Oracle基础笔记
    PL/SQL如何导入dmp文件
    oracle表的基本操作
    sql里面的分页
    truncate table语句和delete table语句的区别
    c++ 时间类型详解 time_t[转]
    C++ 容器:顺序性容器、关联式容器和容器适配器
    XCode 快捷键
  • 原文地址:https://www.cnblogs.com/by-1075324834/p/4541270.html
Copyright © 2020-2023  润新知