树状数组+离散化

Posted linhaitai

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树状数组+离散化相关的知识,希望对你有一定的参考价值。

参考博客:

题目链接:

题意:给出n条平行x或y轴的线段,求线段的交点。

分析:

将  平行 x 轴的直线离散化,只记录它的端点,排序,然后就用树状数组查询。

将 平行y的直线按x 的大小排序,遍历,然后就只考虑它左边的点,遇到是左端点的树状数组就在那个点的y处加一,遇到右端点就在其y处减1。

因为它右端点都在直线的左边,就说明左端点也在,就减一抵消之前的加一。

代码:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<vector>
typedef long long ll;
using namespace std;
const int max_=400005;
struct node1{//开始的直线和后面的平行y轴的直线
   int x1,y1,x2,y2;
   bool operator <(node1 a)const//后面的平行y轴的直线按x排序
     {
         return x1<a.x1;
     }
}edge[max_],c[max_];
struct node2{//离散化平行x轴的直线
   int x,y,type;
   bool operator <(node2 a)const//先按x排序,x相同就左端点优先
     {
         if(x==a.x)
            return type<a.type;
         return x<a.x;

     }
}r[max_];
int Hash[max_];
int bit[max_];
void bit_add(int i,int x,int max_n)//树状数组的单点修改
{
    while(i<max_n)
    {
        bit[i]+=x;
        i+=i&-i;
    }
}
ll bit_getsum(int i)//前i项和
{
    ll ans=0;
    while(i>0)
    {
        ans+=bit[i];
        i-=i&-i;
    }
    return ans;
}
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        int n;
        scanf("%d",&n);
        memset(bit,0,sizeof(bit));
        int tot=1;
        for(int i=0;i<n;i++)
        {
            scanf("%d %d %d %d",&edge[i].x1,&edge[i].y1,&edge[i].x2,&edge[i].y2);
              if(edge[i].x1>edge[i].x2||edge[i].y1>edge[i].y2)//保证左小右大,上大下小
              {
                  swap(edge[i].x1,edge[i].x2);
                  swap(edge[i].y1,edge[i].y2);
              }
             Hash[tot++]=edge[i].x1;
             Hash[tot++]=edge[i].y1;
             Hash[tot++]=edge[i].x2;
             Hash[tot++]=edge[i].y2;
        }
        sort(Hash+1,Hash+tot);
        tot=unique(Hash+1,Hash+tot)-Hash;//去重
        int tot1=0,tot2=0;
        for(int i=0;i<n;i++)
        {
            int x1,y1,x2,y2;
            x1=lower_bound(Hash+1,Hash+tot,edge[i].x1)-Hash;
            y1=lower_bound(Hash+1,Hash+tot,edge[i].y1)-Hash;
            x2=lower_bound(Hash+1,Hash+tot,edge[i].x2)-Hash;
            y2=lower_bound(Hash+1,Hash+tot,edge[i].y2)-Hash;
            if(x1==x2)
            {
                c[tot1++]=node1{x1,y1,x2,y2};
            }
            else
            {
                r[tot2].x=x1,r[tot2].y=y1,r[tot2++].type=0;
                r[tot2].x=x2,r[tot2].y=y2,r[tot2++].type=1;
            }
        }
        sort(c,c+tot1);
        sort(r,r+tot2);
        ll sum=0;
        int j=0;
        for(int i=0;i<tot1;i++)
        {
            while(j<tot2&&(r[j].x<c[i].x1||(r[j].x==c[i].x1&&r[j].type==0)))//遍历在其左边的点(如果右端点等于直线的x,不减)
            {
                if(r[j].type==0)
                    bit_add(r[j].y,1,tot+5);
                else
                    bit_add(r[j].y,-1,tot+5);
                    j++;
            }
            sum+=bit_getsum(c[i].y2)-bit_getsum(c[i].y1-1);//在直线的范围内的点才有效
        }
        printf("%lld
",sum);
    }
}

 

以上是关于树状数组+离散化的主要内容,如果未能解决你的问题,请参考以下文章

严格上升子序列数(树状数组)(离散化优化)

P1908 逆序对(树状数组)(离散化优化)

HDU 5792 World is Exploding (离散化+树状数组)

HDU 4325 离散化+树状数组 或者 不使用树状数组

求逆序数(树状数组+离散化)

LightOJ 1085(树状数组+离散化+DP,线段树)