题意:
一排墙,如果它处于准备状态被攻击了,那么他就被成功攻击。即,若在k时间遭受攻击,则它在k + 1 ~ k + t - 1的时间里面都在准备状态,这时候攻击就是成功攻击。
告诉你怎么攻击的,询问一个点被成功攻击了几次。
解:
据说这题在比赛的时候三小时多只有一个人出。令我很费解的是,时间怎么和空间联系起来呢?
听韦广讲述了一遍,我敲敲看。用树状数组记录空间,时间手动控制(其实是用一个结构体的下标表示时间)。答案 = 每个块被攻击次数(含成功和不成功的被攻击) - 成功防御次数,又是逆向思维。
T了。因为成功防御次数随着时间的增加只增不减,所以可以弄两个数组记录每个位置可以成功防御的时间和已经成功防御的次数。然后就A了。
线段树和树状数组都行,拿来统计每个块被攻击的次数。
感触:
这题真是神啊。但是怎么会这么多人都没做出来呢?做过两道时间和空间结合的题目,都和树状数组和线段树有关。那题是搞个数组记录该回去的时间。http://blog.csdn.net/julyana_lin/article/details/7846451
/*
Pro: 0
Sol:
date:
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <set>
#include <vector>
#define maxn 20010
using namespace std;
int T,n,Q,t,a,b,sub,c[maxn],def_time[maxn],def_num[maxn];
struct Attack{ int s, e; }att[maxn];
char op[10];
void modify(int pos, int val){
while(pos <= n){
c[pos] += val;
pos += (pos & -pos);
}
}
int getsum(int pos){
int sum = 0;
while(pos){
sum += c[pos];
pos -= (pos & -pos);
}return sum;
}
int main(){
scanf("%d",& T);
for(int ca = 1; ca <= T; ca ++){
printf("Case %d:\n",ca);
memset(c,0,sizeof(c)); sub = 0;
memset(def_num,0,sizeof(def_num));
memset(def_time,0,sizeof(def_time));
scanf("%d%d%d",&n,&Q, & t);
for(int j = 0; j < Q; j ++){
scanf("%s",op);
if(op[0] == 'A'){
scanf("%d%d",&att[sub].s,&att[sub].e);
modify(att[sub].s,1);
modify(att[sub].e + 1,-1); sub ++;
}else{
int pos;
scanf("%d",&pos);
for(int i = def_time[pos]; i < sub; i ++){
if(att[i].s <= pos && pos <= att[i].e){
def_num[pos] ++;
def_time[pos] = i + t;
i += (t - 1);
}
}
// int prev;
// for(int i = 0; i < sub; i ++)
// if(att[i].s <= a && att[i].e >= a) { prev = i; sum --; break;}
// for(int i = prev + 1; i < sub; i ++){
// while( (att[i].s > a || att[i].e < a) && i < sub){i ++; }
// - if(i >= sub) break;
// if(i - prev >= t) {sum --; prev = i;}
// }
printf("%d\n",getsum(pos) - def_num[pos]);
}
}
}
return 0;
}
贴线段树的代码:
#include<cstdio>
#include<cstring>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int maxn = 20001;
int sum[maxn<<2];
int col[maxn<<2];
struct pp{
int l,r;
}att[maxn];
int defen[maxn],pos[maxn];
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 t,cases=1,i,j,t0,a,b,n,q;
char s[10];
scanf("%d",&t);
while(t--){
int tot=0;
memset(pos,0,sizeof(pos));
memset(defen,0,sizeof(defen));
scanf("%d%d%d",&n,&q,&t0);att[0].l=att[0].r=0;
memset(rt,0,sizeof(rt));
printf("Case %d:\n",cases++);
while(q--){
scanf("%s",s);
if(s[0]=='A'){
scanf("%d%d",&a,&b);
tot++;
att[tot].l=a;att[tot].r=b;
update(a,b,1,n,1);
}
else {
scanf("%d",&a);
for(i=pos[a];i<=tot;i++){
if(a>=att[i].l&&a<=att[i].r){
pos[a]=i+t0;
defen[a]++;
i+=t0-1;
}
}
printf("%d\n",query(a,1,n,1)-defen[a]);
}
}
}
return 0;
}