您的位置:首页 > 其它

【五校联考2day1】补给站

2016-01-28 18:11 931 查看

Description

WYF为了保证他自己能够吃到足够多的牛排,来补充自己的脑力,所以他建了两个补给站,坐标分别为(ax,ay),(bx,by)。他有n个休息地点,第i个休息地点的坐标是(xi,yi)。每个补给站都有一个补给半径,当一个休息地点在以一个补给站为圆心,该补给站的补给半径为半径的圆中时(包括在圆周上),那个休息地点就会获得补给。现在有m个询问,每个询问会给出第一个补给站的补给半径r1和第二个补给站的补给半径r2,WYF想知道有多少个休息地点会得到补给。

Input

输入的第一行包含2个整数,n与m。

第二行包含4个整数,ax,ay,bx,by。

第3至n+2行包含2个整数x,y。

第n+3至n+m+2行包含两个整数r1,r2。

Output

输出的第1至m行包含1个整数,表示其所对应的询问的答案。

Data Constraint

对于30%的数据:n≤5000,m≤5000.

对于100%的数据:

n≤2*10^5,m≤10^5,ax,ay,bx,by,x,y∈[-100000,100000],r1,r2∈[0,300000]。

分析

这题并没有强制在线,所以有离线做法和在线做法两种。

1.离线做法

其实在此之前,我们可以发现对于一个询问(x,y).先预处理出一个点到两个补给站的距离(a,b)我们只需要用二分或者树状数组线段树求出1..x中有多少个a的个数加上1..y中b的个数,然后再减去有多少个同时满足x也同时满足y的数对的个数。而现在的关键是后面的同时满足的情况。

那么我们可以从一个满足的情况去求两个满足的情况,只用把1..x满足的情况放到树状数组或线段树里面求有多少个同时满足1..y的情况就可以了。而问题是我们每次将1..x放到树状数组里面,然后求完后又清空,这样太过浪费了,所以我们可以将询问排个序,排完序后每次再更新多出来的数——把比上次多出来的放到树状数组里面就可以了。

2.在线做法

我们也可以在上面的思路里面思考。

如何快速求出有多少个同时满足X也同时满足Y的数对的个数。

我们可以用平面直角坐标系里面表示点,那么横坐标表示的是x,纵坐标表示y,那么答案便是ans(X,Y)即在1..x中的1..y这怎么那么像主席树?没错,我们可以用主席树求出1..x中满足第二个距离在1..y中的答案。

在这里我讲讲我打第2种做法的故事。。

首先我听到学长说可以用主席树,于是很兴奋的拿来练手,但是没有仔细想用什么来表示第一维即1..x中的x表示什么(可以是排序后的标号,或者是我用的直接的x),而我直接用了x表示距离,所以在make()时(求主席树时)就比较麻烦(其实也不是很麻烦。。),那时我是这样的:

[code]
void make(ll &x,ll y,ll l,ll r){
    if (!y) return;
    if (!x) ++cnt,x=cnt;
    if (l>r) return;
    ll mid=(l+r)>>1;
    sum[x]+=sum[y];
    make(lef[x],lef[y],l,mid);
    make(rig[x],rig[y],mid+1,r);
}

    for(int i=1;i<=n;i++) insert(root[a[i].x],root[a[i].x],1,ne,a[i].y);
    for(int i=1;i<=now;i++) 
    if (!root[i])root[i]=root[i-1];else make(root[i],root[i-1],1,ne);


a[i]表示的是没有排过序的a数组。ne表示的是y经过离散化后的最大值。

关键是后面的那重循环,我就脑残了。。这样去更新是把每个线段树的节点都遍历了一次,这样的时间复杂度是最高的,相当于做n次线段树,先不说时间,空间就爆了,所以主席树才强调从上一次更新过来,这样的更新并不会太大,所以主席树的空间时间是可以。

后来我才意识到,我们可以也这样做,只不过我们再记录ce[i]表示x=i时的y的各种值,可以用c++里面的库vector

ps:这次用vector终于不爆各种runtime error了。。

[code]这是关键代码
    for(int i=1;i<=M*2;i++) ce[i].clear();
    for(int i=1;i<=n;i++) 
    ce[a[i].x].push_back(a[i].y);
    for(int i=1;i<=now;i++){
        if (ce[i].empty()) root[i]=root[i-1];
        else {
            insert(root[i],root[i-1],1,ne,ce[i][0],0);
            ll len=ce[i].size();
            for(j=1;j<=len-1;j++) 
            insert(root[i],root[i],1,ne,ce[i][j],1);
        }
    }


还有最后大家不要打我——为了方便练习主席树,这里的代码便没有打在线,也就少了个二分而已,大家不要太在意,O(∩_∩)O~

完整代码

离线:

[code]#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#define ll long long
#define db double
using namespace std;
const int N=300005;
const int M=300005;
ll re
,d
,n,m,ax,bx,by,ay,x,y,dat
,t
,num
;
struct nd{
    ll x,y,u;
}b
,a
;
ll sqr(ll x){
    return x*x;
}
bool cmp(nd x,nd y){
    return x.x<y.x;
}
void insert(ll x,ll y){
    while (x<=M){
        t[x]+=y;x+=(x&(-x));
    }
}
ll find(ll x){
    ll ans=0;
    while (x){
        ans+=t[x];x-=(x&(-x));
    }
    return ans;
}
int main(){
    scanf("%lld %lld",&n,&m);
    scanf("%lld %lld %lld %lld",&ax,&ay,&bx,&by);
    for(int i=1;i<=n;i++) {
        scanf("%lld %lld",&x,&y);
        a[i].x=ceil(sqrt(sqr(ax-x)+sqr(ay-y)));a[i].u=i;
        a[i].y=ceil(sqrt(sqr(bx-x)+sqr(by-y)));
        insert(a[i].y,1);
    }
    sort(a+1,a+n+1,cmp);
    for(int i=1;i<=m;i++){
        scanf("%lld %lld",&b[i].x,&b[i].y);
        b[i].u=i;
    }
    sort(b+1,b+m+1,cmp);
    ll l,r,mid,now,id;
    now=0;id=1;
    for(int i=1;i<=m;i++){
        while (a[id].x<=b[i].x){
            now++;insert(a[id].y,-1);id++;
        }
        dat[b[i].u]=now+find(b[i].y);
    }
    for(int i=1;i<=m;i++) printf("%lld\n",dat[i]);
}


在线

[code]#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<vector> 
#include<algorithm>
#define ll long long
#define db double
using namespace std;
const int N=300005;
const int M=300005;
ll n,m,ax,bx,by,ay,x,y,tt,ne,cnt,tot,now,lef[M*30],rig[M*30],root[N+M],sum[M*30],j;
vector<ll>ce[M*2];
struct nd{
    ll x,y;
}b
,a
,c[M+M],d[N+M];
ll sqr(ll x){
    return x*x;
}
bool cmp(nd x,nd y){
    return x.x<y.x;
}
void insert(ll &x,ll y,ll l,ll r,ll z,int op){
    ++cnt,x=cnt;
    lef[x]=lef[y];
    rig[x]=rig[y];
    sum[x]=sum[y]+1;
    if (l==r) return; 
    ll mid=(l+r)>>1;
    if (mid>=z) insert(lef[x],lef[y],l,mid,z,op);else insert(rig[x],rig[y],mid+1,r,z,op);
}
ll find(ll v,ll l,ll r,ll x,ll y){
    if (v==0) return 0;
    if (l==x&&r==y) return sum[v];
    ll mid=(l+r)>>1;
    if (mid>=y) return find(lef[v],l,mid,x,y);else
    if (mid<x) return find(rig[v],mid+1,r,x,y);
    else return find(lef[v],l,mid,x,mid)+find(rig[v],mid+1,r,mid+1,y);
}
int main(){
    scanf("%lld %lld",&n,&m);
    scanf("%lld %lld %lld %lld",&ax,&ay,&bx,&by);
    for(int i=1;i<=n;i++) {
        scanf("%lld %lld",&x,&y);
        a[i].x=ceil(sqrt(sqr(ax-x)+sqr(ay-y)));
        a[i].y=ceil(sqrt(sqr(bx-x)+sqr(by-y)));
        c[++tot].x=a[i].x;c[tot].y=i;
        d[++tt].x=a[i].y;d[tt].y=i;
    }
    for(int i=1;i<=m;i++){
        scanf("%lld %lld",&b[i].x,&b[i].y);
        c[++tot].x=b[i].x;c[tot].y=i+n;
        d[++tt].x=b[i].y;d[tt].y=i+n;
    }
    sort(c+1,c+tot+1,cmp);
    sort(d+1,d+tt+1,cmp);
    c[0].x=-N;d[0].x=-N;
    for(int i=1;i<=tot;i++){
        if (c[i].x!=c[i-1].x) now++;
        if (c[i].y<=n) a[c[i].y].x=now;else b[c[i].y-n].x=now;
    }
    for(int i=1;i<=tt;i++){
        if (d[i].x!=d[i-1].x) ne++;
        if (d[i].y<=n) a[d[i].y].y=ne;else b[d[i].y-n].y=ne;
    } 
    for(int i=1;i<=M*2;i++) ce[i].clear();
    for(int i=1;i<=n;i++) 
    ce[a[i].x].push_back(a[i].y);
    for(int i=1;i<=now;i++){
        if (ce[i].empty()) root[i]=root[i-1];
        else {
            insert(root[i],root[i-1],1,ne,ce[i][0],0);
            ll len=ce[i].size();
            for(j=1;j<=len-1;j++) 
            insert(root[i],root[i],1,ne,ce[i][j],1);
        }
    }
    for(int i=1;i<=m;i++){
        ll dat1=find(root[b[i].x],1,ne,1,ne);
        ll dat2=find(root[now],1,ne,1,b[i].y);
        ll dat3=find(root[b[i].x],1,ne,1,b[i].y);
        printf("%lld\n",dat1+dat2-dat3);
    }
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: