线段树加离散化

  1 #include<cstdio>
  2 #include<algorithm>
  3 using namespace std;
  4 const int maxn=1e5+5;
  5 int a[maxn];
  6 int k[maxn];
  7 struct note
  8 {
  9     int left, right, sum;
 10 }tree[maxn*4];
 11 void pushup(int id)
 12 {
 13     tree[id].sum=tree[id<<1].sum+tree[id<<1|1].sum;
 14 }
 15 void build(int id, int l, int r)
 16 {
 17     tree[id].left=l; tree[id].right=r;
 18     if(l==r) tree[id].sum=0;
 19     else
 20     {
 21         int mid=(l+r)/2;
 22         build(id<<1, l, mid);
 23         build(id<<1|1, mid+1, r);
 24         pushup(id);
 25     }
 26 }
 27 int query(int id, int l, int r)
 28 {
 29     if(l<=tree[id].left && tree[id].right<=r)
 30     {
 31         return tree[id].sum;
 32     }
 33     else
 34     {
 35         int ans=0;
 36         int mid=(tree[id].left+tree[id].right)/2;
 37         if(l<=mid) ans+=query(id<<1, l, r);
 38         if(r>mid) ans+=query(id<<1|1, l, r);
 39         return ans;
 40     }
 41 }
 42 void update(int id, int pos)
 43 {
 44     if(tree[id].left==tree[id].right)
 45     {
 46         tree[id].sum++;
 47     }
 48     else
 49     {
 50         int mid=(tree[id].left+tree[id].right)/2;
 51         if(pos<=mid) update(id<<1, pos);
 52         else update(id<<1|1, pos);
 53         pushup(id);
 54     }
 55 }
 56 int findk(int key, int n)查找对应位置的值。。。
 57 {
 58     int l=1, r=n;
 59     while(l<=r)
 60     {
 61         int mid=(l+r)>>1;
 62         if(k[mid]==key)
 63             return mid;
 64         else
 65         {
 66             if(key<k[mid])
 67                 r=mid-1;
 68             else
 69                 l=mid+1;
 70         }
 71     }
 72 }
 73 int main()
 74 {
 75     int n, m=1;
 76     scanf("%d", &n);
 77     for(int i=1; i<=n; i++)
 78     {
 79         scanf("%d", &a[i]);
 80         k[i]=a[i];
 81     }
 82     sort(k+1, k+1+n);
 83     for(int i=2; i<=n; i++)去重
 84     {
 85         if(k[i]!=k[i-1])
 86             k[++m]=k[i];
 87     }
 88     int t=m;
 89     for(int i=1; i<=t-1; i++)弥补普通离散化的缺陷
 90     {
 91         if(k[i]+1!=k[i+1])
 92         {
 93             k[++m]=k[i]+1;
 94         }
 95     }
 96     sort(k+1, k+1+m);
 97     int ans=0;
 98     build(1, 1, maxn); 
 99     for(int i=1; i<=n; i++)
100     {
101         ans+=query(1, findk(a[i], m)+1, maxn);
102         update(1, findk(a[i], m));
103     }
104     printf("%d", ans);
105 
106 }

普通离散化缺点:

例子一:1-10 1-4 5-10
普通离散化后都变成了[1,4][1,2][3,4]

线段2覆盖了[1,2],线段3覆盖了[3,4],那么线段1被完全覆盖,而实际并没有覆盖。

解决方法:离散化时,要对相邻的数字,在离散化时中间加一个数字

原文地址:https://www.cnblogs.com/dongdong25800/p/9390536.html