hdu4031(线段树+区间更新)

Attack

Time Limit: 5000/3000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others)
Total Submission(s): 1454    Accepted Submission(s): 403


Problem Description
Today is the 10th Annual of “September 11 attacks”, the Al Qaeda is about to attack American again. However, American is protected by a high wall this time, which can be treating as a segment with length N. Al Qaeda has a super weapon, every second it can attack a continuous range of the wall. American deployed N energy shield. Each one defends one unit length of the wall. However, after the shield defends one attack, it needs t seconds to cool down. If the shield defends an attack at kth second, it can’t defend any attack between (k+1)th second and (k+t-1)th second, inclusive. The shield will defend automatically when it is under attack if it is ready.

During the war, it is very important to understand the situation of both self and the enemy. So the commanders of American want to know how much time some part of the wall is successfully attacked. Successfully attacked means that the attack is not defended by the shield.
 

Input
The beginning of the data is an integer T (T ≤ 20), the number of test case.
The first line of each test case is three integers, N, Q, t, the length of the wall, the number of attacks and queries, and the time each shield needs to cool down.
The next Q lines each describe one attack or one query. It may be one of the following formats
1. Attack si ti
  Al Qaeda attack the wall from si to ti, inclusive. 1 ≤ si ≤ ti ≤ N
2. Query p
  How many times the pth unit have been successfully attacked. 1 ≤ p ≤ N
The kth attack happened at the kth second. Queries don’t take time.
1 ≤ N, Q ≤ 20000
1 ≤ t ≤ 50
 

Output
For the ith case, output one line “Case i: ” at first. Then for each query, output one line containing one integer, the number of time the pth unit was successfully attacked when asked.
 

Sample Input
   
   
   
   
2 3 7 2 Attack 1 2 Query 2 Attack 2 3 Query 2 Attack 1 3 Query 1 Query 3 9 7 3 Attack 5 5 Attack 4 6 Attack 3 7 Attack 2 8 Attack 1 9 Query 5 Query 3
 

Sample Output
   
   
   
   
Case 1: 0 1 0 1 Case 2: 3 2
 

Source
The 36th ACM/ICPC Asia Regional Chengdu Site —— Online Contest
 

Recommend
lcy
          本题给定总的范围,攻击+查询次数,然后给定若干攻击或查询次数,每次给出攻击的范围,查询时输出该店受攻击的次数。每个点都有一个防护,每次攻击后要T时间恢复。
          本题的1 ≤ N, Q ≤ 20000都比较大,不能直接模拟。容易想到线段树,但是涉及一个恢复时间不好处理。看了大牛的思路得到启示,可以分开,即每点的当前总的受攻击值与总的防护值分开求,然后最终结果相减。其中求总的攻击值可以用线段树,区间更新+单点查询。求总的防护值时从该点上次受攻击的时间开始循环到当前时间,若该点某时刻被攻击,修改上次被攻击时间,时间加T(T时间后才恢复防护能力),继续循环;否则时间加1继续。总的时间复杂度为O(Q^2).
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;

const int MAXN=200005;
int N,Q,T;
int defend[MAXN];
int pre[MAXN];
//*****************************************************
struct node 
{
	int left,right,add;
}tree[MAXN*4];

struct attack
{
	int left,right;
	attack()
	{
	};
	attack(int l,int r)
	{
		left=l;
		right=r;
	}
}Attack[MAXN];
//1.建立以left,right为左右边界,将数组da中元素存储在首地址从1开始的tree数组中
void build( int id, int left, int right )
{
    tree[id].left = left;
	tree[id].right = right;
	tree[id].add=0;
    if( left == right )
    {
		return ;
    }
    else
    {
        int mid = ( left + right )>>1;        
        build( id <<1, left, mid );
        build( (id<<1)|1, mid + 1, right );
	}
}

//2.对区间[left,right]内每个元素进行加adi操作
void update( int id, int left, int right, int adi)
{
	if(tree[id].left==left&&tree[id].right==right)
	{
		tree[id].add+=adi;
		return ;
	}
	else 
	{
		if(tree[id].add!=0)
		{
			tree[id<<1].add+=tree[id].add;
			tree[(id<<1)|1].add+=tree[id].add;
			tree[id].add=0;
		}
		
		int mid=(tree[id].left+tree[id].right)>>1;
		if(right<=mid)
			update(id<<1,left,right,adi);
		else if(left>mid)
			update((id<<1)|1,left,right,adi);
		else
		{
			update(id<<1,left,mid,adi);
			update((id<<1)|1,mid+1,right,adi);
		}
	}
}

//3.查询pos的值
int query(int id,int pos)
{
	if(tree[id].left==tree[id].right&&tree[id].left==pos)
		return tree[id].add;
	int mid=(tree[id].left+tree[id].right)>>1;
	if(pos<=mid)return tree[id].add+query(id<<1,pos);
	else return tree[id].add+query((id<<1)|1,pos);
}
//*****************************************************************

int main()
{
	int cas,tag=1,l,r,pos,tim,i;
	char cmd[10];
	cin>>cas;
	while(cas--)
	{
		scanf("%d%d%d",&N,&Q,&T);
		memset(defend,0,sizeof(defend));
		memset(pre,0,sizeof(pre));
		tim=0;
		build(1,1,N);
		printf("Case %d:\n",tag++);
		while(Q--)
		{
			scanf("%s",cmd);
			if(cmd[0]=='A')
			{
				scanf("%d%d",&l,&r);
				update(1,l,r,1);
				Attack[tim++]=attack(l,r);
			}
			else
			{
				scanf("%d",&pos);
				if(1==T)
				{
					printf("0\n");
				}
				else
				{
					for(i=pre[pos];i<tim;)
					{
						if(pos>=Attack[i].left&&pos<=Attack[i].right)//只有在发生攻击的时候才看防不防御
						{
							pre[pos]=i+T;
							defend[pos]++;
							i+=T;
						}
						else i++;
					}
					printf("%d\n",query(1,pos)-defend[pos]);//该点总的攻击次数-总的防御次数
				}
			}
		}
	}
	system("pause");
	return 0;
}

你可能感兴趣的:(数据结构,线段树)