线段树—离散化压缩空间优化

来源:互联网 发布:微信域名案 编辑:程序博客网 时间:2024/06/06 15:52

离散化是为了优化线段树的空间。

当遇到空间需求非常大时,可以考虑用离散化,这样能大大压缩空间。


例题:(来源 poj 2528)

【题目描述】有L(L没有给出)段线段(编号为1~L) 1~1000 0000(数组无法定义几千万,所以要用离散化),有 n次操作(1 <= n<= 1 0000),每次操作都是给出l和r,第i次操作的意义就是:把第l段到第r段的线段染色为颜色i。

【输入格式】第一行给出T,表示有T组数据。每组数据给出n表示下来有n个操作。下来n个操作,每行两个整数(l,r)表示把第l段到第r段的线段染色为颜色i。注意后面的染的颜色会覆盖前面的染的颜色。

【输出格式】问最后可以看到的有多少种不一样的颜色。


#include<cstdio>  #include<cstring>  #include<algorithm>  using namespace std;    int len;  bool v[10010];  struct node1  {      int l,r,lc,rc,c;//c=-1时,表示它的范围里海报种类不一;\                        c=0 时,表示它的范围里没有海报;\                        c>0 时,表示它的范围里海报种类为c。   }tr[80010];//80010 > 2*40000 > 2*b[2*n].z  struct node2//离散化用结构体  {      int x,p,z;//x表示原来的值,\                  z表示离散化后的值,\                  p表示x在原来的位置。   }a[20010],b[20010],tmp;</span><pre name="code" class="cpp">  void erfen(int l,int r)//以b[i].x为排序依据,将它从小到大排序  {      int x=l,y=r,m=b[(l+r)/2].x;      while(x<=y)      {          while(b[x].x<m) x++;          while(b[y].x>m) y--;          if(x<=y)          {              tmp=b[x];              b[x]=b[y];              b[y]=tmp;                            x++;y--;          }      }      if(l<y) erfen(l,y);      if(x<r) erfen(x,r);  }    void bt(int l,int r)  {      len++; int now=len;      tr[now].l=l;tr[now].r=r;tr[now].lc=tr[now].rc=-1;tr[now].c=0;      if(l<r)      {          int mid=(l+r)/2;          tr[now].lc=len+1; bt(l,mid);          tr[now].rc=len+1; bt(mid+1,r);      }  }    void change(int now,int l,int r,int k)  {      //if(tr[now].c==k) return ;      if(tr[now].l==l&&tr[now].r==r)      {          tr[now].c=k;          return ;      }      int mid=(tr[now].l+tr[now].r)/2;      int lc=tr[now].lc,rc=tr[now].rc;      if(tr[now].c>0) tr[lc].c=tr[rc].c=tr[now].c;      if(r<=mid) change(lc,l,r,k);      else if(mid+1<=l) change(rc,l,r,k);      else      {          change(lc,l,mid,k);          change(rc,mid+1,r,k);      }      if(tr[lc].c==tr[rc].c&&tr[lc].c>0) tr[now].c=tr[lc].c;      else tr[now].c=-1;  }    void wen(int now,int l,int r)  {      if(tr[now].c>=0)      {          v[tr[now].c]=true;          return ;      }      int mid=(tr[now].l+tr[now].r)/2;      int lc=tr[now].lc,rc=tr[now].rc;      if(tr[now].c>0) tr[lc].c=tr[rc].c=tr[now].c;      if(r<=mid) wen(lc,l,r);      else if(mid+1<=l) wen(rc,l,r);      else      {          wen(lc,l,mid);          wen(rc,mid+1,r);      }  }    int main()  {      int T;      scanf("%d",&T);      while(T--)      {          int n;          scanf("%d",&n);          for(int i=1;i<=n;i++)          {              scanf("%d%d",&a[2*i-1].x,&a[2*i].x);              a[2*i-1].p=2*i-1;              a[2*i].p=2*i;          }          //离散化          for(int i=1;i<=2*n;i++) b[i]=a[i];          erfen(1,2*n);          b[1].z=1;//分配离散值          for(int i=2;i<=2*n;i++)          {              if(b[i].x==b[i-1].x) b[i].z=b[i-1].z;//相同值的离散值相同               else if(b[i].x-b[i-1].x>1) b[i].z=b[i-1].z+2;//难点。保留段与段之间的空位               else b[i].z=b[i-1].z+1;          }          for(int i=1;i<=2*n;i++) a[b[i].p].z=b[i].z;//将离散值转给对应的a          for(int i=1;i<=2*n;i++) a[b[i].p].z=b[i].z;//将离散值转给对应的a          //线段树          len=0; bt(1,b[2*n].z);          for(int i=1;i<=n;i++) change(1,a[2*i-1].z,a[2*i].z,i);          memset(v,false,sizeof(v));          wen(1,1,b[2*n].z);                    int ans=0;          for(int i=1;i<=n;i++)          {              if(v[i]==true) ans++;          }          printf("%d\n",ans);      }      return 0;  }

0 0