HDU 4973 A simple simulation problem.(线段树)

http://acm.hdu.edu.cn/showproblem.php?pid=4973

A simple simulation problem.
Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 451    Accepted Submission(s): 175


Problem Description
There are n types of cells in the lab, numbered from 1 to n. These cells are put in a queue, the i-th cell belongs to type i. Each time I can use mitogen to double the cells in the interval [l, r]. For instance, the original queue is {1 2 3 3 4 5}, after using a mitogen in the interval [2, 5] the queue will be {1 2 2 3 3 3 3 4 4 5}. After some operations this queue could become very long, and I can’t figure out maximum count of cells of same type. Could you help me?
 

Input
The first line contains a single integer t (1 <= t <= 20), the number of test cases.

For each case, the first line contains 2 integers (1 <= n,m<= 50000) indicating the number of cell types and the number of operations.

For the following m lines, each line represents an operation. There are only two kinds of operations: Q and D. And the format is:

“Q l r”, query the maximum number of cells of same type in the interval [l, r];
“D l r”, double the cells in the interval [l, r];

(0 <= r – l <= 10^8, 1 <= l, r <= the number of all the cells)
 

Output
For each case, output the case number as shown. Then for each query "Q l r", print the maximum number of cells of same type in the interval [l, r].

Take the sample output for more details.
 

Sample Input
  
  
1 5 5 D 5 5 Q 5 6 D 2 3 D 1 2 Q 1 7
 

Sample Output
  
  
Case #1: 2 3
 

Source
 


题意:

初始给出1-n的序列,有两个操作:

D l r,将[l,r]区间的每个数都复制一个;

Q l r,询问[l,r]区间内最多的相同数字的个数。

分析:

显然的线段树,但是这个序列的长度会因为D操作变化,即线段长度变化。通过观察发现这个序列永远是sort过的,那么我们只要维护每个数的数量,操作前找到l和r的位置,然后再单点更新、成段更新,成段询问,线段树的综合应用。


/*
 *
 *	Author	:	fcbruce
 *
 *	Date	:	2014-08-24 09:53:20 
 *
 */
#include <cstdio>
#include <iostream>
#include <sstream>
#include <cstdlib>
#include <algorithm>
#include <ctime>
#include <cctype>
#include <cmath>
#include <string>
#include <cstring>
#include <stack>
#include <queue>
#include <list>
#include <vector>
#include <map>
#include <set>
#define sqr(x) ((x)*(x))
#define LL long long
#define itn int
#define INF 0x3f3f3f3f
#define PI 3.1415926535897932384626
#define eps 1e-10

#ifdef _WIN32
	#define lld "%I64d"
#else
	#define lld "%lld"
#endif

#define maxm 
#define maxn 50007

using namespace std;

long long sum[maxn<<2],mul[maxn<<2],maxv[maxn<<2];

inline void pushdown(int k)
{
	if (mul[k])
	{
		int lc=k*2+1,rc=k*2+2;
		mul[lc]+=mul[k];mul[rc]+=mul[k];
		sum[lc]<<=mul[k];sum[rc]<<=mul[k];
		maxv[lc]<<=mul[k];maxv[rc]<<=mul[k];
		mul[k]=0;
	}
}

inline void pushup(int k)
{
	int lc=k*2+1,rc=k*2+2;
	sum[k]=sum[lc]+sum[rc];
	maxv[k]=max(maxv[lc],maxv[rc]);
}

void build(int k,int l,int r)
{
	mul[k]=0;
	if (r-l==1)
	{
		sum[k]=1;
		maxv[k]=1;
		return ;
	}
	
	build(k*2+1,l,l+r>>1);
	build(k*2+2,l+r>>1,r);
	
	pushup(k);
}

void update_plus(int p,LL v,int k,int l,int r)
{
	if (r-l==1)
	{
		sum[k]+=v;
		maxv[k]+=v;
		return ;
	}
	
	pushdown(k);
	int m=l+r>>1;
	if (p<m)
		update_plus(p,v,k*2+1,l,m);
	else
		update_plus(p,v,k*2+2,m,r);
	pushup(k);
}

void update_mul(int a,int b,int k,int l,int r)
{
	if (b<=l || r<=a)	return ;
	if (a<=l && r<=b)
	{
		sum[k]<<=1;
		mul[k]++;
		maxv[k]<<=1;
		return ;
	}
	
	pushdown(k);
	update_mul(a,b,k*2+1,l,l+r>>1);
	update_mul(a,b,k*2+2,l+r>>1,r);
	pushup(k);
}

int query_pos(LL s,int k,int l,int r)
{
	if (r-l==1)	return l;
	
	int lc=k*2+1,rc=k*2+2;
	
	pushdown(k);
	if (s<=sum[lc])
		return query_pos(s,lc,l,l+r>>1);
	else
		return query_pos(s-sum[lc],rc,l+r>>1,r);
}

LL query_sum(int a,int b,int k,int l,int r)
{
	if (b<=l || r<=a)	return 0;
	if (a<=l && r<=b)
	{
		return sum[k];
	}
	
	pushdown(k);
	return query_sum(a,b,k*2+1,l,l+r>>1)+query_sum(a,b,k*2+2,l+r>>1,r);
}

LL query_max(int a,int b,int k,int l,int r)
{
	if (b<=l || r<=a)	return 0;
	if (a<=l && r<=b)
	{
		return maxv[k];
	}
	
	pushdown(k);
	return max(query_max(a,b,k*2+1,l,l+r>>1),query_max(a,b,k*2+2,l+r>>1,r));
}

int main()
{
	#ifndef ONLINE_JUDGE
		freopen("/home/fcbruce/文档/code/t","r",stdin);
	#endif // ONLINE_JUDGE
	
	int T_T,__=0;
	scanf( "%d",&T_T);
	
	while (T_T--)
	{
		printf( "Case #%d:\n",++__);
		
		int n,m;
		scanf( "%d%d",&n,&m);
		
		build(0,0,n);
		
		long long l,r;
		char op;
		for (int i=0;i<m;i++)
		{
			scanf( " %c" lld lld ,&op,&l,&r);
			int a=query_pos(l,0,0,n);
			int b=query_pos(r,0,0,n);
			if (op=='D')
			{
				if (a==b)
				{
					update_plus(a,r-l+1,0,0,n);
				}
				else
				{
					LL v1=query_sum(0,a+1,0,0,n)-l+1;
					LL v2=r-query_sum(0,b,0,0,n);
					update_plus(a,v1,0,0,n);
					update_plus(b,v2,0,0,n);
					if (a+1<b)	update_mul(a+1,b,0,0,n);
				}
			}
			else
			{
				LL MAX=0;
				if (a==b)
				{
					MAX=r-l+1;
				}
				else
				{
					MAX=query_sum(0,a+1,0,0,n)-l+1;
					MAX=max(MAX,r-query_sum(0,b,0,0,n));
					if (a+1<b)	MAX=max(MAX,query_max(a+1,b,0,0,n));
				}
				printf ( lld "\n",MAX);
			}
		}
	}
	
	return 0;
}



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值