标签:线段树
这个题目的难点在于p操作时快速确定没预热炮中的最小编号.我是用线段树为每门炮维护了一个最后可开炮时间,然后每次需要预热一门炮时就用二分加线段树查询满足要求的最小编号.要注意如果一门炮可以开炮时间的结尾恰好是我们查询的时间,我们也要将其看成不可以开炮需要重新预热的(我就在这WA了好几发).
代码如下:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
int const maxn=31000;
long long Min[maxn*4],Max[maxn*4];
void Build(int rt,int l,int r)
{
if(l>=r)
{
Min[rt]=0;
return ;
}
int m=(l+r)/2;
Build(rt*2,l,m);
Build(rt*2+1,m+1,r);
Min[rt]=min(Min[2*rt],Min[2*rt+1]);
}
void update(int rt,int l,int r,int x,int num)
{
if(l>=r)
{
Min[rt]=num;
return ;
}
int m=(l+r)/2;
if(m>=x)
update(rt*2,l,m,x,num);
if(m<x)
update(rt*2+1,m+1,r,x,num);
Min[rt]=min(Min[rt*2],Min[2*rt+1]);
}
long long query(int rt,int l,int r,int ql,int qr)
{
long long ans=0x7fffffff;
if(ql<=l&&qr>=r)
{
return Min[rt];
}
int m=(l+r)/2;
if(m>=ql)
ans=min(ans,query(rt*2,l,m,ql,qr));
if(m<qr)
ans=min(ans,query(rt*2+1,m+1,r,ql,qr));
return ans;
}
int main()
{
//freopen("test0.in","r",stdin);
//freopen("out.txt","w",stdout);
int n,t,p;
while(scanf("%d%d%d",&n,&t,&p)!=EOF)
{
memset(Min,0,sizeof(Min));
while(p--)
{
int x,y;
char str[10];
scanf("%d%s",&x,str);
if(str[0]==‘p‘)
{
int l=1,r=n;
int tmp;
while(l<=r)
{
int m=(l+r)/2;
if(query(1,1,n,l,m)<=x)
r=m-1,tmp=m;
else
l=m+1;
}
update(1,1,n,tmp,x+t*60);
printf("%d\n",tmp);
}
else
{
scanf("%d",&y);
int k=query(1,1,n,y,y);
//cout<<k<<endl;
if(k<=x)
printf("Cannot\n");
else
{
printf("Fire!\n");
update(1,1,n,y,x+t*60);
}
}
}
}
return 0;
}
标签:线段树
原文地址:http://blog.csdn.net/acm_lkl/article/details/45769541