2017-2018 ACM-ICPC Northern Eurasia(A.Archery Tournament)
题目链接:https://vjudge.net/problem/Gym-101630A
题意: n个事件,t=1 代表增加一个圆心为(x,y),半径为 abs(y)的靶子,t=2,代表射击的坐标为(x,y)并且询问是否在已出现的靶子上,如果在则输出第几个事件的编号,否则输出-1。
该题有个坑点:(一开始没看到)一个靶子只能被射击一次。
思路:可以用set存每个靶子的位置,但是需要对靶子按照前后空隙大小进行排序,这样之后我们就可以通过射击点的横坐标对set二分查找出最靠近其的靶子,然后就可以往后遍历是否存在一个靶子使得子弹在上面,但是光这样做在P5 就T了,仔细想了想发现,我们之前排序的作用,一旦我们的 x<x1-abs(y) 那么后面的靶子也不用再遍历了,直接退出循环,这样就会减少很多不必要的操作。
然后还有简单的题解是通过线段树维护暴搜就好了:https://blog.csdn.net/lzc504603913/article/details/83958171
代码:
int n; struct node{ ll x,y,id; bool operator<(const node a) const { return x+abs(y)<a.x-abs(a.y); //排序方法 } }; bool dis(ll x1,ll y1,ll a,ll b) { return (x1-a)*(x1-a)+(y1-b)*(y1-b)<y1*y1; } set<node>s; void run() { scanf("%d",&n); ll t,a,b; for(int i=1;i<=n;i++) { scanf("%lld%lld%lld",&t,&a,&b); if(t==1) { node Node; Node.x=a; Node.y=b; Node.id=i; s.insert(Node); } else{ node tmp; bool flag=0; tmp.x=a; tmp.y=0; set<node>::iterator it=s.lower_bound(tmp); while(it!=s.end()) { ll x1=it->x,y1=it->y; if(dis(x1,y1,a,b)) { flag=true; printf("%lld\n",it->id); s.erase(it); break; } if(it->x-a>abs(it->y)) break;//关键2; it++; } if(!flag) puts("-1"); } } } signed main() { // int t=rd(); // while(t--) run(); return 0; }
线段树的方法:
#include<iostream> #include<deque> #include<memory.h> #include<stdio.h> #include<map> #include<string> #include<algorithm> #include<vector> #include<math.h> #include<stack> #include<queue> #include<bitset> #include<set> #define INF (0x3f3f3f3f) using namespace std; typedef long long int ll; const int MAXN=200010; ll X[MAXN]; ll Y[MAXN]; int tot; vector<int> V[MAXN*30]; int ls[MAXN*30]; int rs[MAXN*30]; int ans; bool check(ll x1,ll y1,ll x2,ll y2){ if((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)<y1*y1) return 1; return 0; } void update(int L,int R,int C,int l,int r,int &rt){ if(!rt) rt=++tot; if(L<=l&&r<=R) { V[rt].push_back(C); return; } int m=(l+r)>>1; if(L<=m) update(L,R,C,l,m,ls[rt]); if(R>m) update(L,R,C,m+1,r,rs[rt]); } void update(int L,int R,int l,int r,int rt){ if(L<=l&&r<=R){ vector<int> tmp; for(auto &t:V[rt]){ if(t!=ans){ tmp.push_back(t); } } V[rt]=tmp; return; } int m=(l+r)>>1; if(L<=m) update(L,R,l,m,ls[rt]); if(R>m) update(L,R,m+1,r,rs[rt]); } void query(int L,int R,int l,int r,int rt){ if(!rt) return; for(auto &t:V[rt]){ if(check(X[t],Y[t],L,R)){ ans=t; return; } } if(l==r) return; int m=(l+r)>>1; if(L<=m) query(L,R,l,m,ls[rt]); else query(L,R,m+1,r,rs[rt]); } int main(){ int N; scanf("%d",&N); int rt=0; for(int i=1;i<=N;i++){ int op,x,y; scanf("%d%d%d",&op,&x,&y); if(op==1){ X[i]=x; Y[i]=y; update(x-y,x+y,i,-INF,INF,rt); } else{ ans=-1; query(x,y,-INF,INF,rt); printf("%d\n",ans); if(ans!=-1) update(X[ans]-Y[ans],X[ans]+Y[ans],-INF,INF,rt); } } return 0; }