hdu 4031 Attack 树状数组
题意:美国有种防护盾,能抵挡恐怖分子的秘密武器,但每次抵挡后,需要t个单位时间去冷却,期间不能起抵挡作用。
思路:我一开始用线段树做,但做到一半就坑爹了~~当修改了线段树的子节点信息时,父节点的左右节点就会产生不一致性,那么也就没法直接修改父节点。
其实这题线段树和树状数组都能做。我们现在把问题分为两个部分:
1.统计但会节点被攻击的次数;
2.统计所有攻击中多少次无效;
那么总的攻击次数减去无效的就是被攻击的次数了。
关于统计被攻击的次数用线段树和树状数组都很好实现。多少次无效的,我们可以定义一个Atc[i][2]数组,记录第i次攻击的区间左右节点。用数组uint[i][0]表示i次攻击后,上次受攻击的时间。uinti[i][1]表示i次攻击后,多少次无效。
每当遇到一次无效攻击,uint[i][0]就加上t(冷却时间),当再次被包括在攻击区间是也一定是无效攻击(已经冷却了).
具体见代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> using namespace std; int list[20005],c[20005]; int n,m; void update(int i,int val) { while(i<=n) { c[i]+=val; i+=i&(-i); } } int Sum(int i) { int s=0; while(i) { s+=c[i]; i-=i&(-i); } return s; } int main() { int t,i,j,x,y,k=0,tt=0,T,q; int Atc[20005][2]; int uint[20005][2]; char str[10]; scanf("%d",&T); while(T--) { scanf("%d%d%d",&n,&q,&t); memset(Atc,0,sizeof(Atc)); memset(uint,0,sizeof(uint)); memset(c,0,sizeof(c));//树状树状清零 for(i=1;i<=n;i++) uint[i][0]=1;//每个单位的初始受攻击时间为1 tt=0; printf("Case %d:\n",++k); for(i=1;i<=q;i++) { scanf("%s",&str); if(str[0]=='A') { tt++; scanf("%d%d",&x,&y); update(x,1);//记录x,y所在区间共被攻击多少次。 update(y+1,-1); Atc[tt][0]=x;//记录攻击区间信息。 Atc[tt][1]=y; } else { scanf("%d",&x); for(j=uint[x][0];j<=tt;) { if(Atc[j][0]<=x&&Atc[j][1]>=x)//如果在区间内,统计一次无效攻击,时间加t,准备统计下次无效攻击 { j+=t; uint[x][0]=j; uint[x][1]++; } else j++; } printf("%d\n",Sum(x)-uint[x][1]);//得出有效攻击次数 } } } return 0; }