奇异旅馆
Time Limit : 3000/1000ms (Java/Other) MemoryLimit : 65535/32768K (Java/Other)
Total Submission(s) : 29 Accepted Submission(s) :15
Problem Description
玩了一天,小A又带着他的小伙伴们来到了当地的奇异旅馆。
这个旅馆共有
n
层,每层分别有
a
i
个床位。由于没有电梯,大家都希望尽可能住在较低的楼层。
现在小A提出了
q
个操作,操作分为两种:
1
.从第
x
i
层开始向上安置
num
i
个小伙伴住宿。
2
.询问前
k
i
层一共已经安置的小伙伴数目。
假设一开始每层楼的床位都是未被使用的,且若操作
1
中
x
i
层及以上的房间无法容纳所要安置的人,则尽可能多地安置,剩余部分忽略。
Input
输入数据的第一行是一个整数
T
,表示测试实例的个数,保证
T
<=
30
。
对于每组测试样例,第一行给出
n
和
q
。(
1<=n<=105
,
1<=q<=105
)
接下来一行共有n个整数
a
i
。(
1<=ai<=109
)
接下来共有
q
行,每行表示一个操作。
第一种操作的给出形式为:
1
xinumi。(
1<=xi<=n
,
1<=numi<=109
)
第二种操作的给出形式为:
2
ki。(
1<=ki<=n
)
题目保证
n
>=50000
且
q
>=
50000
的数据组数不超过
5
组。
Output
每组样例中,对于第一种操作,若
x
i
层及以上的房间无法容纳所要安置的人,输出“overflow”.
对于第二种操作,输出所询问的值。
每个输出数据占一行,且每组数据后输出一个空行。
Sample Input
1
3 5
2 3 5
1 1 4
2 2
1 2 3
2 2
1 3 10
Sample Output
4
5
overflow
【题意】
略。
【思路】
显然对于这么大数据范围,暴力不可行。我们考虑优化的方法。
首先,对于第一种操作,我们肯定是从低往高依次安排,但到后面一定存在一种情况,开始的一段都已经住满,没必要遍历了。于是我们考虑用并查集,将相邻的住满的楼层“连接起来”,然后每次进行操作时,我们便可以快速找到第一个空的楼层。
对于第二种操作,我们用树状数组维护前缀和即可。
具体细节见代码。
#include <cstdio>
#include <cmath>
#include <ctime>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#define mst(a,b) memset((a),(b),sizeof(a))
#define rush() int T;scanf("%d",&T);while(T--)
typedef long long ll;
const int maxn = 100005;
const ll mod = 1e9+7;
const ll INF = 0x3f3f3f3f;
const double eps = 1e-9;
int a[maxn];
int now[maxn];
int pre[maxn];
ll tree[maxn];
int lowbit(int x)
{
return x&(-x);
}
void add(int pos,ll val)
{
while(pos<maxn)
{
tree[pos]+=val;
pos+=lowbit(pos);
}
}
ll query(int pos)
{
ll ans=0;
while(pos>0)
{
ans+=tree[pos];
pos-=lowbit(pos);
}
return ans;
}
int dfs(int x)
{
int t,r=x;
while(pre[x]!=x)
{
x=pre[x];
}
while(r!=x)
{
t=pre[r];
pre[r]=x;
r=t;
}
return x;
}
void join(int a,int b)
{
int A=dfs(a);
int B=dfs(b);
if(A>B)
{
pre[B]=A;
}
else pre[A]=B;
}
int main()
{
/*freopen("c://ccpc//problem 1002 data.txt","r",stdin);
freopen("c://ccpc//problem 1002 results.txt","w",stdout);*/
int n,q;
int op,pos,w;
rush()
{
scanf("%d%d",&n,&q);
mst(now,0);
mst(tree,0);
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
pre[i]=i;
}
pre[n+1]=n+1;
for(int i=0; i<q; i++)
{
scanf("%d",&op);
if(op==1)
{
scanf("%d%d",&pos,&w);
while(w>0)
{
pos=dfs(pos);
if(pos==n+1)
{
puts("overflow");
break;
}
if(a[pos]-now[pos]>w)
{
now[pos]+=w;
add(pos,w);
w=0;
}
else
{
w-=(a[pos]-now[pos]);
add(pos,a[pos]-now[pos]);
now[pos]=a[pos];
join(pos,pos+1);
}
}
}
else if(op==2)
{
scanf("%d",&pos);
ll ans=query(pos);
printf("%I64d\n",ans);
/*for(int j=1;j<=n;j++)
{
printf("%d %I64d\n",j,query(j));
}*/
}
}
puts("");
}
return 0;
}