NEERC 2017-2018 A Archery Tournament(分块or动态加点线段树)

题目链接:https://codeforces.com/group/xrTA2IaQje/contest/254939/attachments

 

题目大意:1表示加一个中心在x,y的靶子,半径为y,2表示往x,y射一枪,如果一个靶子都射不中输出-1,否则输出被射中的靶子是第几个操作被加入的并删除这个靶子,保证每个靶子之间没有交叉

 

题目思路:

方法1:

直接暴力分块,每左边x-y能到-2e9,右边能到2e9,分4e6一个块,分成1000块,然后每次都对(x-y)/4e6~(x+y)/4e6中的块都加入这个圆,每次射击就查询这个块中有没有被射中且没被删除的,删除以后vis变1即可。此方法非常佛系,能不能过得看运气,但是代码很短,当实在没思路时不失为一种选择

 

方法2:

使用线段树动态开点,与众不同的是线段树每个点都是一个set,这个非常神奇。对x-y到x+y的点全都加这个圆的编号,不需要push_up,push_down,因为查询的时候一直到查询到或者实在没了才会return,没找到会一直下去,所以只要乖乖呆在路径上总能被找到

 

以下是代码:

方法1:

#include<bits/stdc++.h>
 
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define ll long long
#define inf 0x3f3f3f3f
const int MAXN = 2e5+5;
const int MOD = 1e9+7;
int n,t,x,y;
struct node{
    int x,y;
}a[MAXN];
vector<int>v[MAXN];
int vis[MAXN];
int main()
{
    while(~scanf("%d",&n)){
        rep(i,0,1e3)v[i].clear();
        memset(vis,0,sizeof(vis));
        rep(i,1,n){
            scanf("%d%d%d",&t,&x,&y);
            if(t==1){
                int l=(x-y+2e9)/4e6,r=(x+y+2e9)/4e6;
                rep(j,l,r){
                    v[j].push_back(i);
                }
                a[i].x=x,a[i].y=y;
            }
            else{
                int pos=(x+2e9)/4e6;
                int len=v[pos].size(),flag=0;
                rep(j,0,len-1){
                    int u=v[pos][j];
                    if(vis[u])continue;
                    if((ll)(a[u].x-x)*(a[u].x-x)+(ll)(a[u].y-y)*(a[u].y-y)<(ll)a[u].y*a[u].y){
                        flag=1;
                        printf("%d\n",u);
                        vis[u]=1;
                    }
 
                }if(!flag)puts("-1");
            }
        }
    }
    return 0;
}

 

方法2:

#include<bits/stdc++.h>
 
using namespace std;
#define rep(i,a,b) for(ll i=a;i<=b;i++)
#define per(i,a,b) for(ll i=a;i>=b;i--)
#define ll long long
#define inf 0x3f3f3f3f
const ll MAXN = 2e5+5;
const ll MOD = 1e9+7;
ll n,t,x,y,rt;
ll cnt;
set<ll>s[MAXN*20];
ll lson[MAXN*20],rson[MAXN*20],ans;
struct node{
    ll x,y;
}a[MAXN];
void update(ll &rt,ll l,ll r,ll L,ll R,ll val,ll flag){
    if(!rt)rt=++cnt;
    if(L<=l&&r<=R){
        if(flag)s[rt].insert(val);
        else s[rt].erase(val);
        return;
    }
    ll mid=(l+r)>>1;
    if(L<=mid)update(lson[rt],l,mid,L,R,val,flag);
    if(R>mid)update(rson[rt],mid+1,r,L,R,val,flag);
}
void query(ll rt,ll l,ll r,ll x,ll y){
    if(!rt)return;
    if(l<=x&&x<=r){
        for(set<ll>::iterator it=s[rt].begin();it!=s[rt].end();it++){
            ll pos=*it;
            if((a[pos].x-x)*(a[pos].x-x)+(a[pos].y-y)*(a[pos].y-y)<a[pos].y*a[pos].y){
                ans=pos;
                return;
            }
        }
    }
    if(l==r)return;
    ll mid=(l+r)>>1;
    if(x<=mid)query(lson[rt],l,mid,x,y);
    else query(rson[rt],mid+1,r,x,y);
}
int main()
{
    while(~scanf("%I64d",&n)){
        rep(i,1,20*n)s[i].clear();
        memset(lson,0,sizeof(lson));
        memset(rson,0,sizeof(rson));
        rt=0;
        cnt=0;
        rep(i,1,n){
            scanf("%I64d%I64d%I64d",&t,&x,&y);
            a[i].x=x,a[i].y=y;
            if(t==1){
                update(rt,-1e9,1e9,x-y,x+y,i,1);
            }
            else{
                ans=-1;
                query(rt,-1e9,1e9,x,y);
                if(ans==-1)puts("-1");
                else {
                    printf("%I64d\n",ans);
                    update(rt,-1e9,1e9,a[ans].x-a[ans].y,a[ans].x+a[ans].y,ans,0);
                }
            }
        }
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值