bzoj1807: [Ioi2007]Pairs 彼此能听得见的动物对数

很有趣的一道题233

一维送分的,排序后弄个指针扫描维护当前最远能够听见的位置即可

二维我会肝两次分治,后来看claris博客发现可以把曼哈顿距离换成切比雪夫距离,要满足|xi-xj|<=D&&|yi-yj|<=D

这样就好做了,转化成区间问题扫描线+线段树水

三维不管高,然后同样的转换,因为m很小对于每个动物都可以枚举去第几层,用二维前缀和出解即可

然而卡空间卡空间边界超久。。。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>

#define mp(k,i,j) mp[k][i][j+105]
using namespace std;
typedef long long LL;

int n,D,m,c[110000];
void solve1()
{
    scanf("%d%d%d",&n,&D,&m);
    for(int i=1;i<=n;i++)scanf("%d",&c[i]);
    sort(c+1,c+n+1);
    int r=0;LL ans=0;
    for(int l=1;l<=n;l++)
    {
        while(r<n&&c[r+1]-c[l]<=D)r++;
        ans+=r-l;
    }
    printf("%lld\n",ans);
}

//--------------------------------------------------------------------------------

int s[210000];
int lowbit(int x){return x&-x;}
void change(int x,int k)
{
    while(x<=n)
    {
        s[x]+=k;
        x+=lowbit(x);
    }
}
int getsum(int x)
{
    int ret=0;
    while(x>0)
    {
        ret+=s[x];
        x-=lowbit(x);
    }
    return ret;
}
struct node2{int x,y;}p[110000];                        int lslen,ls[110000];
bool node2_cmp(node2 n1,node2 n2){return n1.x<n2.x;}    int LB(int x){return lower_bound(ls+1,ls+lslen+1,x)-ls;}
                                                        int UB(int x){return upper_bound(ls+1,ls+lslen+1,x)-ls;}
struct line
{
    int op,x,y;
    line(){}
    line(int OP,int X,int Y){op=OP;x=X;y=Y;}
}li[310000];int lilen;
bool line_cmp(line l1,line l2){return l1.x==l2.x?l1.op<l2.op:l1.x<l2.x;}
void solve2()
{
    scanf("%d%d%d",&n,&D,&m);lilen=0;
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&p[i].x,&p[i].y),p[i].x*=2,p[i].y*=2;
        int xx=(p[i].x+p[i].y)/2,yy=(p[i].x-p[i].y)/2;
        p[i].x=xx,p[i].y=yy;
        ls[++lslen]=yy;
        
        li[++lilen]=line(0,p[i].x-D,p[i].y);
        li[++lilen]=line(1,p[i].x,p[i].y);
        li[++lilen]=line(2,p[i].x+D,p[i].y);
    }
    sort(ls+1,ls+lslen+1);
    lslen=unique(ls+1,ls+lslen+1)-ls-1;
    sort(li+1,li+lilen+1,line_cmp);
    
    LL ans=0;
    memset(s,0,sizeof(s));
    for(int i=1;i<=lilen;i++)
    {
        if(li[i].op==0)change(LB(li[i].y),1);
        else if(li[i].op==1)ans+=getsum(UB(li[i].y+D)-1)-getsum(LB(li[i].y-D)-1)-1;
        else change(LB(li[i].y),-1);
    }
    printf("%lld\n",ans/2);
}

//--------------------------------------------------------------------------------

struct node3{int x,y,z;}o[210000];
int mp[80][210][210];
void solve3()
{
    int x,y,z;
    scanf("%d%d%d",&n,&D,&m);
    memset(mp,0,sizeof(mp));
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d%d",&o[i].x,&o[i].y,&o[i].z),o[i].x*=2,o[i].y*=2;
        int xx=(o[i].x+o[i].y)/2,yy=(o[i].x-o[i].y)/2;
        o[i].x=xx,o[i].y=yy;
        mp(o[i].z,o[i].x,o[i].y)++;
    }
    for(int k=1;k<=m;k++)
        for(int i=1;i<=200;i++)
            for(int j=-100;j<=100;j++)
                mp(k,i,j)+=mp(k,i-1,j)+mp(k,i,j-1)-mp(k,i-1,j-1);
    LL ans=0;
    for(int i=1;i<=n;i++)
    {
        for(int k=1;k<=m;k++)
        {
            int W=D-abs(o[i].z-k);if(W<0)continue;
            ans+=mp(k,min(200,o[i].x+W),min(100,o[i].y+W))
                -mp(k,min(200,o[i].x+W),max(-100,o[i].y-W-1))
                -mp(k,max(0,o[i].x-W-1),min(100,o[i].y+W))
                +mp(k,max(0,o[i].x-W-1),max(-100,o[i].y-W-1));
        }
        ans--;
    }
    printf("%lld\n",ans/2);
}

int main()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    int B;
    scanf("%d",&B);
    if(B==1)solve1();
    else if(B==2)solve2();
    else solve3();
    return 0;
}

 

posted @ 2018-10-25 13:02  AKCqhzdy  阅读(248)  评论(0编辑  收藏  举报