HDU 4400 Mines(好题!分两次计算距离)
http://acm.hdu.edu.cn/showproblem.php?pid=4400
题意:
在笛卡尔坐标中有多个炸弹,每个炸弹有一个坐标值和一个爆炸范围。现在有多次操作,每次引爆一个炸弹,问每次操作会有多少个炸弹爆炸。
思路:
需要注意的是一个炸弹爆炸后会引起别的炸弹爆炸,然后别的炸弹爆炸后又会引起别的炸弹爆炸。
可以考虑bfs,但是必须需要优化,首先对x坐标进行离散化,然后将该坐标的y值和id值(第几个炸弹)存入multiset中,不同的x存入不同的multiset中。当我们进行寻找时,首先可以确定x的范围,当确定了x的范围之后,对于该x值我们又可以确定y的范围,这样只需要在multiset中进行二分查找即可。不得不说这个做法实在是太妙了。
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<set> 5 #include<queue> 6 #include<cstring> 7 using namespace std; 8 const int maxn = 100000+5; 9 10 int n, num; 11 int x[maxn],y[maxn],d[maxn],b[maxn]; 12 bool del[maxn]; 13 14 struct node 15 { 16 int y,id; 17 node(int y, int id):y(y),id(id){} 18 bool operator< (const node& rhs) const 19 { 20 return y<rhs.y; 21 } 22 }; 23 24 multiset<node> s[maxn]; 25 multiset<node>::iterator ly, ry, it; 26 27 void solve() 28 { 29 priority_queue<int> q; 30 memset(del,false,sizeof(del)); 31 int m; scanf("%d",&m); 32 while(m--) 33 { 34 int t; scanf("%d",&t); t--; 35 if(del[t]) {puts("0");continue;} 36 while(!q.empty()) q.pop(); 37 q.push(t); 38 del[t] = true; 39 int ans = 0; 40 while(!q.empty()) 41 { 42 ans++; 43 t = q.top(); q.pop(); 44 int lx = lower_bound(b,b+num,x[t]-d[t])-b; 45 int rx = upper_bound(b,b+num,x[t]+d[t])-b; 46 for(int i=lx;i<rx;i++) 47 { 48 int dis = d[t]-abs(x[t]-b[i]); 49 ly = s[i].lower_bound(node(y[t]-dis,0)); 50 ry = s[i].upper_bound(node(y[t]+dis,0)); 51 for(it=ly;it!=ry;it++) 52 { 53 if(!del[it->id]) 54 { 55 del[it->id] = true; 56 q.push(it->id); 57 } 58 } 59 s[i].erase(ly,ry); 60 } 61 } 62 printf("%d\n",ans); 63 } 64 } 65 66 int main() 67 { 68 //freopen("in.txt","r",stdin); 69 int kase = 0; 70 while(~scanf("%d",&n) && n!=0) 71 { 72 printf("Case #%d:\n",++kase); 73 for(int i=0;i<n;i++) 74 { 75 scanf("%d%d%d",&x[i],&y[i],&d[i]); 76 b[i] = x[i]; 77 } 78 sort(b,b+n); 79 num = unique(b,b+n)-b; 80 for(int i=0;i<n;i++) s[i].clear(); 81 for(int i=0;i<n;i++) 82 { 83 int tmp = lower_bound(b,b+num,x[i])-b; 84 s[tmp].insert(node(y[i],i)); 85 } 86 solve(); 87 } 88 return 0; 89 }