时间限制: 2 Sec 内存限制: 32 MB
提交: 61 解决: 37
[提交][状态][讨论版][命题人:外部导入]
题目描述
食堂有N个打饭窗口,现在正到了午饭时间,每个窗口都排了很多的学生,而且每个窗口排队的人数在不断的变化。
现在问你第i个窗口到第j个窗口一共有多少人在排队?
输入
输入的第一行是一个整数T,表示有T组测试数据。
每组输入的第一行是一个正整数N(N<=30000),表示食堂有N个窗口。
接下来一行输入N个正整数,第i个正整数ai表示第i个窗口最开始有ai个人排队。(1<=ai<=50)
接下来每行有一条命令,命令有四种形式:
(1)Add i j,i和j为正整数,表示第i个窗口增加j个人(j不超过30);
(2)Sub i j,i和j为正整数,表示第i个窗口减少j个人(j不超过30);
(3)Query i j,i和j为正整数,i<=j,表示询问第i到第j个窗口的总人数;
(4)End 表示结束,这条命令在每组数据最后出现;
每组数据最多有40000条命令。
输出
对于每组输入,首先输出样例号,占一行。
然后对于每个Query询问,输出一个整数,占一行,表示询问的段中的总人数,这个数保持在int以内。
样例输入
1 10 1 2 3 4 5 6 7 8 9 10 Query 1 3 Add 3 6 Query 2 7 Sub 10 2 Add 6 3 Query 3 10 End
样例输出
Case 1: 6 33 59
今天搞懂了分块大法,明天开始莫队
#include<stdio.h>
#include<iostream>
#include<math.h>
#include<string>
#include<string.h>
using namespace std;
int table[30005];
int block[30005];
int main()
{
int t;
scanf("%d",&t);
int tt=1;
while(t--)
{
printf("Case %d:\n",tt);
tt++;
memset(table,0,sizeof(table));
memset(block,0,sizeof(block));
int n;
scanf("%d",&n);
int ai;
int num=sqrt(n);
int k;
int m;
for(int i=1;i<=n;i++)
{
scanf("%d",&table[i]);
if(i%num>0)k=i/num+1;
else k=i/num;
block[k]+=table[i];
}
string s;
int a,b;
while(cin>>s)
{
int k1,k2;
if(s=="End"){
break;
}
else{
cin>>a>>b;
if(s=="Query"){
k1=a%num>0?a/num+1:a/num;
k2=b%num>0?b/num+1:b/num;
int sum=0;
if(k1==k2){
for(int i=a;i<=b;i++)
{
sum+=table[i];
}
}
else{
for(int i=a;i<=k1*num;i++)
{
sum+=table[i];
}
for(int i=k1+1;i<k2;i++){
sum+=block[i];
}
for(int i=(k2-1)*num+1;i<=b;i++){
sum+=table[i];
}
}
printf("%d\n",sum);
}
else if(s=="Add"){
table[a]+=b;
k1=a%num>0?a/num+1:a/num;
block[k1]+=b;
}
else{
table[a]-=b;
k1=a%num>0?a/num+1:a/num;
block[k1]-=b;
}
}
}
}
}