hdu4400 STL应用 查找思维题

http://acm.hdu.edu.cn/showproblem.php?pid=4400

Problem Description
Terrorists put some mines in a crowded square recently. The police evacuate all people in time before any mine explodes. Now the police want all the mines be ignited. The police will take many operations to do the job. In each operation, the police will ignite one mine. Every mine has its "power distance". When a mine explodes, any other mine within the power distance of the exploding mine will also explode. Please NOTE that the distance is Manhattan distance here.

More specifically, we put the mines in the Cartesian coordinate system. Each mine has position (x,y) and power distance d.

The police want you to write a program and calculate the result of each operation.
 

Input
There are several test cases.
In each test case:
Line 1: an integer N, indicating that there are N mines. All mines are numbered from 1 to N.
Line 2…N+1: There are 3 integers in Line i+1 (i starts from 1). They are the i-th mine’s position (xi,yi) and its power distance di. There can be more than one mine in the same point.
Line N+2: an integer M, representing the number of operations.
Line N+3...N+M+2 : Each line represents an operation by an integer k meaning that in this operation, the k-th mine will be ignited. It is possible to ignite a mine which has already exploded, but it will have no effect.

1<=M<=N<=100000,0<=xi,yi<=10^9,0<=di<=10^9

Input ends with N=0.
 

Output
For each test case, you should print ‘Case #X:’ at first, which X is the case number starting from 1. Then you print M lines, each line has an integer representing the number of mines explode in the correspondent operation.
 

Sample Input
  
  
3 0 0 0 1 1 2 2 2 2 3 1 2 3 0
 

Sample Output
  
  
Case #1: 1 2 0
/***
hdu4400 STL应用
题目大意:在二维坐标系中给出一些点,每次爆炸一些点,每个点都有一个爆炸半径,在半径内的点会接着爆炸,已经爆炸过的不再爆炸,问每次给定一个爆炸点
          能有多少炸弹在此次爆炸。注意:点和点之间的距离为曼哈顿距离,而且有重合的点
解题思路:离散化横坐标,对对于每一个横坐标建立一个vector容器,然后将每个容器里的点从小到大排列,然后从小到大排序横坐标,利用lower_bound查找即可。
*/
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
const int maxn = 110005;
const int inf = 2000000005;

struct node
{
    int y,dis;
    node(){}
    node(int y,int dis)
    {
        this->y=y;
        this->dis=dis;
    }
    bool operator <(const node &other)const
    {
        if(y==other.y)return dis<other.dis;
        return y<other.y;
    }
};
vector<node>vec[maxn];

struct point
{
    int x,y,dis;
    point(){}
    point(int x,int y,int dis)
    {
        this->x=x;
        this->y=y;
        this->dis=dis;
    }

}po[maxn];
queue<point>q;

int n,m,Hash[maxn];

int main()
{
    int tt=0;
    while(~scanf("%d",&n))
    {
        if(n==0)break;
        for(int i=0;i<maxn;i++)///各个容器清空
        {
            vec[i].clear();
        }
        int num=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d%d",&po[i].x,&po[i].y,&po[i].dis);
            Hash[num++]=po[i].x;///储存所有点的横坐标
        }
        sort(Hash,Hash+num);
        num=unique(Hash,Hash+num)-Hash;///去重,num为去重后的个数
        for(int i=1;i<=n;i++)///对于每个横坐标x视为一个容器
        {
            int id=lower_bound(Hash,Hash+num,po[i].x)-Hash;
            vec[id].push_back(node(po[i].y,po[i].dis));
        }
        for(int i=0;i<num;i++)///每个横坐标容器排序
        {
            sort(vec[i].begin(),vec[i].end());
        }
        scanf("%d",&m);
        printf("Case #%d:\n",++tt);
        for(int i=1;i<=m;i++)
        {
            int k,ret=0;;
            scanf("%d",&k);
            while(!q.empty())q.pop();
            vector<node>::iterator it1,it2,it;
            q.push(point(po[k].x,po[k].y,po[k].dis));
            while(!q.empty())
            {
                point now=q.front();
                q.pop();
                ///确定可及横坐标范围
                int x=lower_bound(Hash,Hash+num,now.x-now.dis)-Hash;
                int y=upper_bound(Hash,Hash+num,now.x+now.dis)-Hash;
                for(;x<y;x++)
                {
                    int t=Hash[x];///t为正在查找的横坐标点
                    int yy=now.dis-abs(t-now.x);///该横坐标下的纵坐标可及最大值
                    int id=lower_bound(Hash,Hash+num,t)-Hash;
                    it1=lower_bound(vec[id].begin(),vec[id].end(),node(now.y-yy,-1));
                    it2=lower_bound(vec[id].begin(),vec[id].end(),node(now.y+yy,inf));
                    it=it1;
                    for(;it1<it2;it1++)
                    {
                        node tmp=*it1;
                        q.push(point(t,tmp.y,tmp.dis));
                        ret++;
                    }
                    vec[id].erase(it,it2);///删除已经经历过的点
                }
            }
            printf("%d\n",ret);
        }
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值