教室中的座位

教室中的座位

Time Limit:10000MS  Memory Limit:65536K
Total Submit:78 Accepted:7

Description

教室中座位的数目有多有少,并不总是相同。每到考试的时候就会出现有些教室有多余的座位的情况,因为考试期间这些多余的座位也不能让别人使用。这实在是一种浪费。要是这些座位能够自由移动该多好啊!虽然现实中,这个想法无法实现,可是不妨碍我们在这里臆想一下! 
为了简化问题,我们假设所有的教室在同一层楼上。假设这一层楼被分成了一个个方格(行数和列数都不超过1000),每个方格是一间教室。开始时,每间教室都有1个座位。然后,我们可以对这些教室的座位进行处理:给某间教室添加座位,从某间教室搬走座位,从一间教室向另一间教室转移座位,查看某间教室的座位数。 

Input

输入的第一行是测试用例个数T (1 ≤ T ≤ 10)。 
对于每个测试用例,第一行是整数Q (1 < Q < 100,000), 后面紧跟 Q 行,每行是一个处理操作。共有4种操作: A x y m 表示给位于(x, y)的教室添加m个座位; D x y m 表示从位于(x, y)的教室搬走m个座位,如果该教室的座位数不足,则搬走其所有座位; M x1 y1 x2 y2 m表示从位于(x1, y1)的教室向位于(x2, y2)的教室转移m个座位,如果位于(x1, y1)的教室中的座位数不足m个,则搬走其所有座位;S x1 y1 x2 y2表示查询以(x1, y1) 与(x2, y2)这两个点确定的矩形范围内的教室中的座位总数目。 0 ≤ x1, y1, x2, y2, x, y < 1000,0 ≤ m < 100. 

Output

对于每个测试用例, 输出 "Case X:" X是测试用例的序号. 
对于每个查询操作输出查询结果。 

Sample Input

2
3
S 1 1 2 2
A 1 1 3
S 1 1 1 1
4
S 1 1 1 1
D 1 1 2
S 1 1 1 2
M 1 1 2 2 100

Sample Output

Case 1:
4
4
Case 2:
1
1

这题花了好多时间。。。尝试了好几种方法都没能AC。。

比如一维线段树,树状数组这两种方法我反正没能AC。。可能是这两种方法掌握的不好。。所以没能找到AC的办法。。

最后查资料。。原来还有其他的线段树,可以用二维线段树的。。

最后套用某个大牛的二维线段树模版,终于AC!



下面是AC代码:

#include<iostream>
using namespace std;
# define HMax 3005
# define AMax 3005
struct sub_tree
{
	int la,ra,Max;
};
struct main_tree
{
	sub_tree A[AMax];
	int l,r;
}H[HMax];

int num;
void sub_bulid(int l,int r,int la,int ra,int t1,int t)
{
	H[t].A[t1].la=la;
	H[t].A[t1].ra=ra;

	H[t].A[t1].Max=(ra-la+1)*(r-l+1);

	if(la==ra) return;
	int mid=(la+ra)/2;

	sub_bulid(l,r,la,mid,2*t1,t);
	sub_bulid(l,r,mid+1,ra,2*t1+1,t);
}
void bulid(int l,int r,int la,int ra,int t)
{
	H[t].l=l;
	H[t].r=r;
	sub_bulid(l,r,la,ra,1,t);

	if(l==r) return;

	int mid=(l+r)/2;
	bulid(l,mid,la,ra,2*t);
	bulid(mid+1,r,la,ra,2*t+1);
}
void sub_insert(int a,int L,int t1,int t)
{

	if(H[t].A[t1].Max+L>=0)
	{
		H[t].A[t1].Max+=L;	
	}
	else 
	{
		H[t].A[t1].Max=0;
	}
	if(H[t].A[t1].la == H[t].A[t1].ra) return ;
	if(a<=H[t].A[2*t1].ra) sub_insert(a,L,2*t1,t);
	else sub_insert(a,L,2*t1+1,t);
}

void insert(int h,int a,int L,int t)
{
	sub_insert(a,L,1,t);

	if(H[t].l==H[t].r) return;
	if(h<=H[2*t].r) insert(h,a,L,2*t);
	else insert(h,a,L,2*t+1);
}
int sub_query(int A1,int A2,int t1,int t)
{
	if(H[t].A[t1].la==A1 && H[t].A[t1].ra==A2) 
		return num+=H[t].A[t1].Max;

	if(A2<=H[t].A[2*t1].ra) return sub_query(A1,A2,2*t1,t);

	else if(A1>=H[t].A[2*t1+1].la) return sub_query(A1,A2,2*t1+1,t);
	else 
	{
		sub_query(A1,H[t].A[2*t1].ra,2*t1,t);
		sub_query(H[t].A[2*t1+1].la,A2,2*t1+1,t);
	}
}
void query(int h1,int h2,int A1,int A2,int t)
{
	if(H[t].l==h1 && H[t].r==h2) 
	{
		num=sub_query(A1,A2,1,t);
		return;
	}
	if(h2<=H[2*t].r) query(h1,h2,A1,A2,2*t);
	else if(h1>=H[2*t+1].l) query(h1,h2,A1,A2,2*t+1);
	else
	{
		query(h1,H[2*t].r,A1,A2,2*t);
		query(H[2*t+1].l,h2,A1,A2,2*t+1);
	}
}
void solveA()
{
	int x,y,m;
	scanf("%d%d%d",&x,&y,&m);
	insert(x,y,m,1);
}
void solveD()
{
	int x,y,m,t;
	scanf("%d%d%d",&x,&y,&m);
	num=0;
	query(x,x,y,y,1);
	if(num>=m)
		t=m;
	else
		t=num;

	insert(x,y,-t,1);
}
void solveM()
{
	int x1,y1,x2,y2,m,t;

	scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&m);

	num=0;
	query(x1,x1,y1,y1,1);
	if(num>=m)
		t=m;
	else
		t=num;

	insert(x1,y1,-t,1);
	insert(x2,y2,t,1);
	
}
void solveS()
{
	int x1,y1,x2,y2,t;

	scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
	
	if(x1>x2)
		t=x1,x1=x2,x2=t;
	if(y1>y2)
		t=y1,y1=y2,y2=t;

	num=0;
	query(x1,x2,y1,y2,1);
	
	printf("%d\n",num);
	
}
int main()
{
//	freopen("G:\\text.txt","r",stdin);

	int n,i,t,k=0;
	cin>>t;
	while(t--)
	{	
		bulid(0,1000,0,1000,1);

		scanf("%d",&n); 	
		printf("Case %d:\n",++k);	
		
		for(i=0;i<n;i++)
		{
			getchar();
			char ch=getchar();
			if(ch=='A')
				solveA();
			if(ch=='D')
				solveD();
			if(ch=='M')
				solveM();
			if(ch=='S')
				solveS();
		}
	}
	
	return 0;
	
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值