zoukankan      html  css  js  c++  java
  • xdoj 1174 Links 优先队列+线段树


    链接:
    Links

    题意:
    坐标系上有n个塔,对于任意两个塔,如果存在一个平行于坐标轴的矩形仅包含这两个塔,可以将它们连接。(包含的含义是位于矩形内部或其边缘)输出最多能够连接多少对塔。

    思路:
    我们只要对于每个点(xi,yi),处理y坐标小于yi的点,
    对于x坐标小于xi的点,按x坐标递增顺序维护一个y坐标单调递减队列,
    对于x坐标大于xi的点,按x坐标递减顺序维护一个y坐标单调递减队列,
    统计一下就是答案。
    这样做的复杂度为o(n^2)
    现在的问题是如何维护(1-当前点)的单调队列的大小。
    可以用线段树分割维护单调队列。因为单调队列的右端是变化的左端永远是1。
    所以可以先访问线段树的右端,然后记录当前单调队列左端最大值,然后再线段树左端进行二分,合并。
    例如线段树是(1-8)现在要求(1-6)的单调队列。(1-6)显然分成(1-4)(5-6)。
    我们先访问(5-6),然后记录其单调队列的大小,和其左端的值left。
    然后再(1-4)的单调队列中二分left的值,然后去掉小于left的部分,然后再记录。
    这种做法复杂度为o(nlogn^2)

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <cstdlib>
    #include <algorithm>
    #include <vector>
    using namespace std;
    typedef long long int64;
    const int maxn = 100000+10 , maxv = maxn*4 , inf = 2000000000;
    int n,m,ys[maxn],Right;
    int64 ans;
    struct node { int x,y; } v[maxn];
    vector <node> t[maxv];
     
    void init()
    {
        scanf("%d",&n);
        for (int i=1;i<=n;i++)
            scanf("%d%d",&v[i].x,&v[i].y);
        ans=0;
    }
     
    void Sort(int l,int r)
    {
        int i=l,j=r;
        node mid=v[rand()%(r-l+1)+l];
        do
        {
            while ( v[i].x<mid.x || ( v[i].x==mid.x && v[i].y<mid.y ) ) i++;
            while ( v[j].x>mid.x || ( v[j].x==mid.x && v[j].y>mid.y ) ) j--;
            if (i<=j) 
                swap(v[i++],v[j--]);
        }
        while (i<=j);
        if (l<j) Sort(l,j);
        if (i<r) Sort(i,r);
    }
     
    int binary( int x )
    {
        int l=1,r=m;
        while (l<r) 
        {
            int mid=(l+r)>>1;
            if ( ys[mid]<x ) l=mid+1; 
            else r=mid;
        }
        return l;
    }
     
    void pre()
    {
        for (int i=1;i<=n;i++) 
            v[i].y*=-1,ys[i]=v[i].y;
        sort(ys+1,ys+1+n);
        m=1;
        for (int i=2;i<=n;i++)
            if (ys[i]!=ys[m]) ys[++m]=ys[i];
     
        Sort(1,n);
        for (int i=0;i<maxv;i++) t[i].clear();
    }
     
    void ins( int x,int a,int b,int l,int r,int X,int Y )
    {
        while ( t[x].size() && t[x][t[x].size()-1].y<=Y )
            t[x].pop_back();
        node v; v.x=X,v.y=Y;
        t[x].push_back(v);
     
        if ( a<=l && r<=b ) return;
        int mid=(l+r)>>1;
        if ( a<=mid ) ins(x+x,a,b,l,mid,X,Y);
        if ( mid<b ) ins(x+x+1,a,b,mid+1,r,X,Y);
    }
     
    int64 find( int x,int a,int b,int l,int r )
    {
        if ( a<=l && r<=b ) 
        {
            int L=0,R=t[x].size()-1;
            if ( R<0 || t[x][R].x<=Right ) return 0;
            while ( L<R )
            {
                int Mid=(L+R)>>1;
                if ( t[x][Mid].x>Right ) R=Mid; 
                else L=Mid+1;
            } 
            Right=t[x][t[x].size()-1].x;
            return t[x].size()-R;
        }
        int mid=(l+r)>>1;
        int64 ans=0;
        if ( mid<b ) ans+=find(x+x+1,a,b,mid+1,r);
        if ( a<=mid) ans+=find(x+x,a,b,l,mid);
        return ans;
    }
     
    void solve()
    {
        for (int i=1;i<=n;i++)
        {
            Right=-inf;
            int rank=binary(v[i].y);
            ans+=find(1,1,rank,1,m);
            ins(1,rank,rank,1,m,v[i].x,rank);
        }
    }
     
    void del()
    {
            Sort(1,n);
            for (int i=1;i<=n;)
            {
                    int tot=0;
                    while ( i+1<=n && v[i].x==v[i+1].x ) i++,tot++;
                    ans-=int64(tot);
                    i++;
            }
     
            for (int i=1;i<=n;i++) swap(v[i].x,v[i].y);
     
            Sort(1,n);
            for (int i=1;i<=n;)
            {
                    int tot=0;
                    while ( i+1<=n && v[i].x==v[i+1].x ) i++,tot++;
                    ans-=int64(tot);
                    i++;
            }
    }
     
    int main()
    {
            init();
         
            pre();
            solve();
            pre();
            solve();
            del();
             
            printf("%lld
    ",ans);
     
        return 0;
    }
    
  • 相关阅读:
    解剖SQLSERVER 第十二篇 OrcaMDF 行压缩支持(译)
    解剖SQLSERVER 第十三篇 Integers在行压缩和页压缩里的存储格式揭秘(译)
    解剖SQLSERVER 第十四篇 Vardecimals 存储格式揭秘(译)
    解剖SQLSERVER 第十五篇 SQLSERVER存储过程的源文本存放在哪里?(译)
    解剖SQLSERVER 第七篇 OrcaMDF 特性概述(译)
    解剖SQLSERVER 第八篇 OrcaMDF 现在支持多数据文件的数据库(译)
    解剖SQLSERVER 第九篇 OrcaMDF现在能通过系统DMVs显示元数据(译)
    解剖SQLSERVER 第十篇 OrcaMDF Studio 发布+ 特性重温(译)
    解剖SQLSERVER 第十一篇 对SQLSERVER的多个版本进行自动化测试(译)
    解剖SQLSERVER 第三篇 数据类型的实现(译)
  • 原文地址:https://www.cnblogs.com/nanf/p/xdoj1174.html
Copyright © 2011-2022 走看看