CH Round #46A 磁力块

还是一道好题的

对于一个磁石是否被吸引,有两个关键字:距离和质量。(二维偏序??)

好像是很厉害的分块姿势,先按第一关键字排序,在块中按第二关键字排

进行bfs,对于当前磁石,有1~k-1个块是第一关键字全部小于等于当前磁石的,那么暴力从块首往后,找到第一个第二关键字大于当前磁石属性的,那么前面都捡走,以后可以从这里开始找。

暴力枚举第k个块找答案。

一个优化就是找k的时候直接比较当前块的最大值就行了,因为当前的属性肯定是>kmin,<kmax滴

(垃圾CH本机AC提交WA幸好最后我搞对了)

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;

int n;
struct node{LL dis,m,p,r;}a[310000];bool v[310000];
bool cmp1(node n1,node n2){return n1.m<n2.m;}
bool cmp2(node n1,node n2){return n1.dis<n2.dis;}

int block,st[310000];
struct LIST
{
    LL p,r;
}list[310000];
int be[610];LL mx[610];

int findk(LL p)
{
    for(int i=1;i<=block;i++)
        if(p<mx[i])return i;
    return block+1;
}

int main()
{
    freopen("1.in","r",stdin);
    freopen("1.out","w",stdout);
    
    LL xx,yy,x,y;
    scanf("%lld%lld%lld%lld%d",&xx,&yy,&list[1].p,&list[1].r,&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld%lld%lld%lld%lld",&x,&y,&a[i].m,&a[i].p,&a[i].r);
        a[i].dis=(x-xx)*(x-xx)+(y-yy)*(y-yy);
    }
    sort(a+1,a+n+1,cmp1);
    
    block=(int(sqrt(double(n+1))))+1;
    for(int i=1;i<=n;i++)st[i]=(i-1)/block+1;
    for(int i=1;i<=block;i++)
    {
        int St=(i-1)*block+1,Ed=min(i*block,n);mx[i]=a[Ed].m;
        if(St<=Ed)sort(a+St,a+Ed+1,cmp2);
    }
    
    for(int i=1;i<=block;i++)be[i]=1;
    memset(v,false,sizeof(v));
    int head=1,tail=2,ans=0;
    while(head<tail)
    {
        LL p=list[head].p,r=list[head].r;
        int k=findk(p);
        for(int i=1;i<=k-1;i++)
        {
            for(int j=be[i];j<=block&&(i-1)*block+j<=n;j++)
            {
                int u=(i-1)*block+j;
                if(a[u].dis>r*r){be[i]=j;break;}
                {
                    if(v[u]==false)
                    {
                        v[u]=true;
                        ans++;
                        list[tail].p=a[u].p, list[tail].r=a[u].r;
                        tail++;
                    }
                }
            }
        }
        if(k!=block+1)
        {
            for(int j=be[k];j<=block&&(k-1)*block+j<=n;j++)
            {
                int u=(k-1)*block+j;
                if(a[u].dis>r*r)break;
                else if(a[u].m<=p)
                {
                    if(v[u]==false)
                    {
                        v[u]=true;
                        ans++;
                        list[tail].p=a[u].p, list[tail].r=a[u].r;
                        tail++;
                    }
                }
            }
        }
        head++;
    }
    printf("%d\n",ans);
    return 0;
}

 

posted @ 2018-08-06 20:25  AKCqhzdy  阅读(165)  评论(0编辑  收藏  举报