题目大意:
给你n个点的坐标(xi,yi),然后再给你m个炸弹,每个炸弹描述如下:两个数:c,d,c=0时表示把x坐标等于d的点全部销毁,c=1表示把y坐标等于d的点全部销毁。题目问你每个炸弹能销毁几个点(已经被其他炸弹销毁的不能再销毁)。
(N<=100,000) ,(M<=100,000),坐标范围小于109
题解:
数据量比较大,可以看出应使用O(nlogn)的算法。
map+set+pair
如果你能想到C++的STL这个题目就比较简单了。
首先使用map来离散化坐标,然后用STL中的set<pair<int,int> >开xset[i],yset[i]数组。
xset[i]记录横坐标(以后提及的坐标都是离散化之后的坐标)为i的点的集合,yset[i]记录做坐标为i的点的集合。
每次出现一个炸弹,以销毁x坐标的炸弹为例,直接输出xset[x]的尺寸就是答案,然后将yset中对应的点删除。
由于每个点至多删除一次,所以时间复杂度为O(nlogn)。
#include<iostream> #include<map> #include<set> #include<cstring> #include<cstdio> #include<utility> using namespace std; const int maxn=210000; int tx[maxn],ty[maxn]; map<int,int>mymap; multiset<pair<int,int> >xset[maxn],yset[maxn]; multiset<pair<int,int> >::iterator it; int n,m; int main() { while(scanf("%d%d",&n,&m),n||m) { int tot=0; mymap.clear(); for(int i=0;i<maxn;i++) { xset[i].clear(); yset[i].clear(); } for(int i=1;i<=n;i++) { int x,y; scanf("%d%d",&x,&y); if(mymap.count(x)==0) { tot++; mymap[x]=tot; } if(mymap.count(y)==0) { tot++; mymap[y]=tot; } int lx=mymap[x],ly=mymap[y]; xset[lx].insert(make_pair(lx,ly)); yset[ly].insert(make_pair(lx,ly)); } for(int i=1;i<=m;i++) { int c,z; scanf("%d%d",&c,&z); if(c==0) { if(mymap.count(z)<=0){printf("0\n");continue;} int x=mymap[z]; int num=0; for(it=xset[x].begin();it!=xset[x].end();it++) { num++; tx[num]=it->first; ty[num]=it->second; } for(int j=1;j<=num;j++) yset[ty[j]].erase(make_pair(tx[j],ty[j])); xset[x].clear(); printf("%d\n",num); } else { if(mymap.count(z)<=0){printf("0\n");continue;} int y=mymap[z]; int num=0; for(it=yset[y].begin();it!=yset[y].end();it++) { num++; tx[num]=it->first; ty[num]=it->second; } for(int j=1;j<=num;j++) xset[tx[j]].erase(make_pair(tx[j],ty[j])); yset[y].clear(); printf("%d\n",num); } } printf("\n"); } return 0; }