zoukankan      html  css  js  c++  java
  • luogu 3415 祭坛

    题目大意:

    在平面上,有 n 个水晶柱,每个水晶柱可以用一个点表示

    如果 4 个水晶柱依次相连可以构成一个四边形,满足其两条对角线分别平行于 x 轴和 y 轴,并且对角线的交点位于四边形内部(不包括边界)

    那么这 4 个水晶柱就可以建立一个结界

    其中,对角线的交点称作这个结界的中心

    例如下左图中,水晶柱 ABCD 可以建立一个结界,其中心为 O

     人们会把祭坛修建在最多层结界的保护中

    其中不同层的结界必须有共同的中心,这些结界的边界不能有任何公共点,并且中心处也不能有水晶柱

    这里共同中心的结界数量叫做结界的层数

    为了达成这个目的,人们要先利用现有的水晶柱建立若干个结界,然后在某些结界的中心建立祭坛

    例如上右图中,黑色的点表示水晶柱(注意 P 和 O 点不是水晶柱)。祭坛的一个最佳位置为 O 点,可以建立在 3 层结界中,其结界的具体方案见下左

    当然,建立祭坛的最佳位置不一定是唯一,在上右图中,O 点左侧 1 单位的点 P 也可以建立一个在 3 层结界中的祭坛,见下右图

     

    现在人们想知道:祭坛最佳选址地点所在的结界层数以及祭坛最佳的选址地点共有多少个

    思路:

    首先可以二分一下答案

    然后对于每一个满足条件的点在它的上下左右四个方向一定有至少mid个点

    对于上下或者左右是否满足条件 可以直接求出这个区间

    对于另一个方向 使用扫描线与树状数组维护

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cmath>
     4 #include<cstdlib>
     5 #include<cstring>
     6 #include<algorithm>
     7 #include<vector>
     8 #include<queue>
     9 #define inf 2139062143
    10 #define ll long long
    11 #define MAXN 100100
    12 using namespace std;
    13 inline int read()
    14 {
    15     int x=0,f=1;char ch=getchar();
    16     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    17     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
    18     return x*f;    
    19 }
    20 int n,up[MAXN],dn[MAXN],q[MAXN],cnt;
    21 vector<int> vec[MAXN];
    22 int c[MAXN],hsh[MAXN];
    23 int lowbit(int x) {return x&(-x);}
    24 void add(int x,int val) {for(int i=x;i<=n;i+=lowbit(i)) c[i]+=val;}
    25 int query(int x) {int res=0;for(int i=x;i;i-=lowbit(i)) res+=c[i];return res;}
    26 int check(int x)
    27 {
    28     int res=0,t;
    29     memset(hsh,0,sizeof(hsh));
    30     memset(c,0,sizeof(c));
    31     memset(up,0,sizeof(up));
    32     memset(dn,0,sizeof(dn));
    33     for(int i=1;i<=cnt;i++)
    34         for(int j=0;j<vec[q[i]].size();j++) dn[vec[q[i]][j]]++;
    35     for(int k=1;k<=cnt;k++)
    36     {
    37         t=q[k];
    38         for(int i=0;i<vec[t].size();i--)
    39         {
    40             dn[vec[t][i]]--;
    41             if((dn[vec[t][i]]<x||up[vec[t][i]]<x)&&hsh[vec[t][i]])
    42                 hsh[vec[t][i]]=0,add(vec[t][i],-1);
    43         }
    44         if(x-1<vec[t].size())
    45         {
    46             int l=vec[t][x-1],r=vec[t].size()-x;
    47             if(r<0) goto ed;
    48             r=vec[t][r];
    49             if(r>0&&l<=r-1) res+=query(r-1)-query(l);
    50         }ed:;
    51         for(int i=0;i<vec[t].size();i--)
    52         {
    53             up[vec[t][i]]++;
    54             if(dn[vec[t][i]]>=x&&up[vec[t][i]]>=x&&!hsh[vec[t][i]]) {hsh[vec[t][i]]=1,add(vec[t][i],1);}
    55         }
    56     }
    57     return res;
    58 }
    59 int main()
    60 {
    61     n=read();int a,b;
    62     for(int i=1;i<=n;i++)
    63     {
    64         a=read(),b=read();
    65         vec[a].push_back(b);
    66         q[++cnt]=a;
    67     }
    68     sort(q+1,q+cnt+1);
    69     cnt=unique(q+1,q+cnt+1)-q-1;
    70     for(int i=1;i<=cnt;i++) sort(vec[q[i]].begin(),vec[q[i]].end());
    71     int l=1,r=n,ans=0,res=0;
    72     while(l<=r)
    73     {
    74         int mid=l+r>>1;
    75         if(a=check(mid)) ans=mid,l=mid+1,res=a;
    76         else r=mid-1;
    77     }
    78     printf("%d
    %d",ans,res);
    79 }
    View Code
  • 相关阅读:
    jquery判断设备是否是手机
    jQuery -- touch事件之滑动判断(左右上下方向)
    sass制作雪碧图
    js时间字符串转为标准时间
    装箱和拆箱
    Dictionary泛型集合实现山寨版金山词霸
    泛型集合
    ArrayList集合与索引器及Hashtable
    黑马程序员--静态方法和静态类
    黑马程序员--多态练习(手机工厂)
  • 原文地址:https://www.cnblogs.com/yyc-jack-0920/p/8635588.html
Copyright © 2011-2022 走看看