[离散+二分]HDU4400 Mines
来源:互联网 发布:mac pdf reader pro 编辑:程序博客网 时间:2024/04/27 23:09
题意:给n个平面上的炸弹,每个炸弹有一个爆炸范围d,爆炸的时候会引爆d范围内的炸弹(注意距离为曼哈顿距离),这些炸弹可以又炸其他炸弹。然后m次询问,每次引爆编号num的炸弹,输出爆炸的次数,如果已经炸过了就输出0。
因为是平面点,我用了以y升序的mulitset,内部是有序的,就不用再去排序了,而且自带上下二分函数。STL大法好啊。
离散的过程是,x相同的就压入同一个Mset,不同的以x的升序压入Mset。
其实这题就是WA在离散上,果然基本功太渣了ORZ。
以后离散都用sort+unique+lower_bound写了,代码简单,排序复杂度是NlogN,用lower_bound插入是logN,总的复杂度是o(2NlogN)=o(NlogN)。
每次询问的时候先二分出x的左右界,然后枚举二分出y的上下界,然后已经炸了就标记。离散的时候学习了lower_bound和upper_bound,这里写的二分都用这两个函数搞了,代码容易不少。
看代码。
#include<map>#include<string>#include<cstring>#include<cstdio>#include<cstdlib>#include<cmath>#include<queue>#include<vector>#include<iostream>#include<algorithm>#include<bitset>#include<climits>#include<list>#include<iomanip>#include<stack>#include<set>#include<ctime>#define pb push_back#define pii pair<int,int>#define LL long long intusing namespace std;const int MN=100505;struct node{ //记录炸弹 int x,y,d;}bom[MN];struct st{ //多重集的元素 int y,x; st(){} st(int a,int b){y=a,x=b;} bool operator<(st a)const{ return y<a.y; }};int mak[MN]; //离散 multiset<st>:: iterator L,R;multiset<st> mst[MN];bool boom[100015];c //标记是否炸了 int main(){ int n,m,ca=1; while( scanf("%d", &n) != EOF && n ) { printf("Case #%d:\n", ca++); memset( mak, 0, sizeof(mak) ); memset( boom, 0, sizeof(boom) ); for(int i = 0; i <= n +10; ++i) mst[i].clear(); for(int i = 0; i < n; ++i){ scanf("%d %d %d", &bom[i].x, &bom[i].y, &bom[i].d); mak[i]=bom[i].x; } sort(mak, mak + n); int cnt = unique(mak, mak + n) - mak; for(int i=0;i<n;++i){ int p=lower_bound(mak, mak + cnt, bom[i].x) - mak; //效率是logN mst[p].insert( st(bom[i].y, i) ); } /*sort(bom, bom + n); 按x排序。 这一段是之前的离散,虽然可以AC但是效率不如用STL的高,复杂度多加一个N。 int cnt = 1; mak[0] = bom[0].x; mst[0].insert( st(bom[0].y,bom[0].nb) ); for(int i=1;i<n;++i) { if(bom[i].x!=mak[cnt-1]){mak[cnt]=bom[i].x;mst[cnt++].insert( st(bom[i].y,bom[i].nb) ); } else mst[cnt-1].insert( st(bom[i].y,bom[i].nb) ); } sort(bom, bom + n, cmp); 还原成输入的顺序。 一定要还原成输入的顺序,因为下面询问给的序号是输入时的。 */ scanf("%d", &m); while( m-- ) { int num, ans = 0; scanf( "%d", &num); num -= 1; //我们的序号是从0开始离散的 if( boom[ num] ) { puts("0"); continue; } boom[ num] = 1; queue< int >q; q.push(num); while( !q.empty() ) { int now = q.front(); q.pop(); ans += 1; int l = lower_bound( mak, mak + cnt, bom[ now].x - bom[now].d ) - mak; //二分出x的范围 int r = upper_bound( mak, mak + cnt, bom[now].x + bom[now].d ) - mak; for(int i = l; i < r; ++i) { int ef = bom[ now].d - abs( bom[ now].x - mak[i] ); //算出曼哈顿距离下的范围 L = mst[i].lower_bound( st(bom[ now].y - ef, 0) ); //二分出y的范围 R = mst[i].upper_bound( st(bom[ now].y + ef, 0) ); for(multiset<st>:: iterator it = L; it != R; ++it) { if( !boom[it -> x]) { boom[it -> x] = 1; //标记爆炸 q.push(it -> x); //入队看是否又引爆了其他的 } } mst[i].erase(L, R); //这一步并不是必要的,因为上面已经标记是不是炸了,而且我不清楚删除的效率如何,但在OJ上有这一步更快。 } } printf("%d\n", ans); } }}
0 0
- [离散+二分]HDU4400 Mines
- 二分 【离散化】
- hdu4400 BFS+STL
- ZOJ_3790_Consecutive Blocks(离散化+二分/单调队列)
- poj 1151 Atlantis 二分查找+离散化
- poj 3368 离散化+线段树+二分
- POJ2391 Floyd+离散化+二分+DINIC
- poj2528线段树+离散化+二分
- HDU4343[Interval query]--倍增思想+二分+离散
- 【noip2015】跳石头 二分+离散化
- hdu4400 STL应用 查找思维题
- C# Mines(布雷)
- HDU 4400 Mines
- ZOJ 3755 Mines
- HDU 4400-Mines-KDtree
- Mines in DP
- ZOJ1654 离散化+二分图匹配 匈牙利算法
- POJ 2528 线段树+坐标离散化+哈希+二分
- Java开发中的23种设计模式详解(转)
- iostream stdlib fstream io.h 头文件的作用
- csv文件打开中文乱码解决方法
- 第十二周 项目二 摩托车继承自行车和机动车
- 第十三周 项目一 (3)Animal 抽象类加入名字。
- [离散+二分]HDU4400 Mines
- 菜鸟学Android(五):XML约束之DTD2
- 数据结构
- zookeeper windows 入门安装和测试
- Java线程可见性
- GITHUB之GIT BASH使用教程
- 零散知识点.....
- android log system
- restful的理解