题目链接
http://codeforces.com/contest/948/problem/C
刚讲完树状数组的第一场cf就遇到了,然而没做出来,次日怒补之,同时写篇题解自省。
题目大意
每天新造一堆体积为v[i]的雪,同时所有的雪堆都融化t[i]的体积,体积<=0时雪堆消失,问每天融掉的雪的总体积。
解题分析
令num[i]为第i天的剩余雪堆数,rem[i]为将在该天消失的雪的总体积,则第i天融掉的雪的总体积为num[i]*t[i]+rem[i]。
用树状数组sum[i]维护t[i]的前缀和,则对每个v[i],可以用二分O(lognlogn)地算出在将第j天消失,继而从i到j-1的num++(修改两点即可),同时rem[j]+=剩余体积。
总时间复杂度O(nlognlogn)。
AC代码
#include<bits/stdc++.h>
#define LL long long
#define lowbit(x) x&-x
using namespace std;
const int MAXN = 100010;
template<typename T> inline void R(T &x) {
char ch = getchar(); x = 0;
for (; ch < '0'; ch = getchar());
for (; ch >= '0'; ch = getchar()) x = x * 10 + ch - '0';
}
int n;
int v[MAXN];
int t[MAXN];
LL sum[MAXN];
LL num[MAXN];
LL rem[MAXN];
LL ask(int x)
{
LL ans = 0 ;
for(; x ; x-=lowbit(x) ) ans += sum[x];
return ans ;
}
void add(int x,int y)
{
for(; x<=n ; x+=lowbit(x) ) sum[x] += y;
}
int main()
{
cin>> n;
for(int i = 1; i <= n; i ++) R(v[i]);
for(int i = 1; i <= n; i ++) R(t[i]);
for(int i = 1; i <= n; i ++) add(i , t[i]);
for(int i = 1; i <= n; i ++){
int l = i, r = n , res = n + 1;
while(l <= r){
int mid = (l + r)/2;
LL tmp = ask(mid) - ask(i - 1);
if( tmp > v[i] ) res = mid, r = mid - 1;
else l = mid + 1;
}
rem[res] += v[i] - (ask(res - 1) - ask(i - 1));
num[i] ++;
num[res] --;
}
for(int i = 1; i <= n; i ++){
num[i] += num[i-1] ;
cout<< num[i] * t[i] + rem[i] <<' ';
}
cout<< endl;
return 0;
}