牛客题解 | 香槟塔
题目
题解:
难度:三星
考察点: 模拟,线段树,二分
解法一:模拟
这个题的测试数据可能比较水,没想到暴力也能卡过去。设置一个数组\(b\)来记录每一层的香槟体积,对于每一次查询操作,直接输出\(b_k\)即可;对于每一次修改操作,如果\(v+b_x>a_x\),则香槟会继续流入下一层,直到不能流为止,否则香槟在当前层终止,并修改当前层的体积。
#include "bits/stdc++.h"
using namespace std;
const int maxn=200000+10;
int a[maxn],b[maxn],n,m;
int main()
{
//freopen("in.txt","r",stdin);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
while(m--){
int op,x,v;
scanf("%d",&op);
if(op==1){
scanf("%d",&x);
printf("%d\n",b[x]);
}else{
scanf("%d%d",&x,&v);
while(x<=n&&v>0){
int tmp=a[x]-b[x];
if(tmp<v){ v-="tmp;" b[x]="a[x];" x++; }else{ b[x]+="v;" v="0;" } return 0; ``` **解法二:二分+线段树** 线段树是一种快速处理区间问题的数据结构,对于区间更新,区间求合等问题能在$o(log_2n)$的时间复杂度内完成,具体可以参见codeforces上这份[教程](https: codeforces.com blog entry 18051) 用线段树维护每一层的剩余容量,对于查询操作,直接总容量减去剩余容量即可;对于更新操作,因为从第$x$层开始往下,剩余容量是单调递增的,因此具有可二分性,可以二分从$x$层倒入能到达的层数$y$,则第$x$到$y-1$层的剩余容量都区间修改为$0$,第$y$层容量修改为$x$到$y$的总剩余容量减去$v$。因为有二分和线段树,所以复杂度为$o(n(log_2n)^2)$ . ```cc #include "bits stdc++.h" using namespace std; const int maxn="2e5+100;" typedef long ll; struct node{ left,right; ll sum,val; }tree[maxn<<2]; n,m; a[maxn]; void pushup(int rt){ tree[rt].sum="(LL)(R-L+1)*c;" pushdwon(int tree[rt<<1].sum="(tree[rt<<1].right" - tree[rt<<1].left + 1) * tree[rt].val; tree[rt<<1|1].sum="(tree[rt<<1|1].right" tree[rt<<1|1].left tree[rt<<1].val="tree[rt<<1|1].val" = tree[rt].val="(LL)c;" build(int l,int r,int tree[rt].left="l,tree[rt].right=r;" if(l return; mid="(L+R)/2;" build(l,mid,rt<<1); build(mid+1,r,rt<<1|1); pushup(rt); update(int c,int l="tree[rt].left,R=tree[rt].right;" if(tree[rt].val!="-1)" pushdwon(rt); if(r<="mid)" update(l,r,c,rt<<1); else>mid) update(l,r,c,rt<<1|1);
else{
update(l,mid,c,rt<<1);
update(mid+1,r,c,rt<<1|1);
}
pushup(rt);
}
LL query(int l,int r,int rt){
int L=tree[rt].left,R=tree[rt].right;
if(l==L&&r==R) return tree[rt].sum;
if(tree[rt].val!=-1) pushdwon(rt);
int mid=(L+R)/2;
if(r<=mid) return query(l,r,rt<<1);
if(l>mid) return query(l,r,rt<<1|1);
return query(l,mid,rt<<1)+query(mid+1,r,rt<<1|1);
}
int main()
{
//freopen("in.txt","r",stdin);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
build(1,n,1);
while(m--){
int op,x;
LL v;
scanf("%d",&op);
if(op==1){
scanf("%d",&x);
printf("%lld\n",a[x]-query(x,x,1));
}else{
scanf("%d%lld",&x,&v);
int l=x,r=n,y=-1;
while(l<=r){
int mid=(l+r)/2;
if(query(x,mid,1)>=v){
y=mid;
r=mid-1;
}else l=mid+1;
}
if(y==-1){
update(x,n,0,1);
}else if(x==y){
int tmp=query(x,x,1);
update(x,x,tmp-v,1);
}else{
int tmp=query(x,y,1);
update(x,y-1,0,1);
update(y,y,tmp-v,1);
}
}
}
return 0;
}
</v){>

浙公网安备 33010602011771号