题目大意:
给你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;
}