被攻击的次数等于 总的攻击次数 减去 成功防守的次数
这道题目其实主要考如何计算成功防守的次数。
用数组last[]记录上一次被打击的时间,即记录上次询问后某个点防守到了第几次进攻(第一次进攻都能防守住)
每防守住一次,就过t0-1次进攻,继续判断接下来的第t0次进攻有没有包括(即攻击到)询问的点
num[]记录到目前为止,总共被打击了几次。
参考:http://www.cnblogs.com/wuyiqi/archive/2012/01/11/2319025.html
代码如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxn 22222
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
int last[maxn],num[maxn];
int sum[maxn*4];
struct node
{
int l,r;
};
node att[maxn];
int T,N,Q,t;
int p,tot,casei;
char ch[10];
int read()
{
int ans = 0;
char ch = getchar();
while(ch < '0' || ch > '9') ch = getchar();
while(ch >= '0' && ch <= '9'){
ans = ans * 10 + ch - '0';
ch = getchar();
}
return ans;
}
void update(int L,int R,int l,int r,int rt){
if(L<=l&&r<=R){//完全覆盖就不再更新了,否则就退化成O(n),必然导致超时
sum[rt]++;
return ;
}
int m=(l+r)>>1;
if(L<=m) update(L,R,lson);
if(R>m) update(L,R,rson);
}
int query(int p,int l,int r,int rt){//依次把树上的覆盖次数相加,加到底的时候就是某个点的覆盖次数了
if(l==r){
return sum[rt];
}
int m=(l+r)>>1;
int ret=0;
ret+=sum[rt];
if(p<=m) return ret+query(p,lson);
else return ret+query(p,rson);
}
int main()
{
int i,j;
att[0].l=att[0].r=-1;
scanf("%d",&T);
while(T--)
{
tot=0;
casei++;
printf("Case %d:\n",casei);
memset(last,0,sizeof(last));
memset(num,0,sizeof(num));
memset(sum,0,sizeof(sum));
scanf("%d%d%d",&N,&Q,&t);
for(j=1;j<=Q;j++)
{
int L;
scanf("%s",ch);
if(ch[0]=='A')
{
tot++;
att[tot].l=read();
att[tot].r=read();
update(att[tot].l,att[tot].r,1,N,1);
}
else
{
p=read();
for(i=last[p];i<=tot;i++)
{
if(att[i].l<=p&&p<=att[i].r)
{
last[p]=i+t;
num[p]++;
i+=t-1;
}
}
printf("%d\n",query(p,1,N,1)-num[p]);
}
}
}
return 0;
}