题意:n个碟子,第i个碟子能装a[i]水,若第i个碟子装满,则多余的水流到下一层碟子,下一层依次类推
初始碟子为空,m个操作,op1:第x个碟子装p单位水,op2:询问第k个碟子有多少水.n,m<=2e5,a[i]<=1e9;
法1:
第i个碟子装水,二分最远能流到第x个,用线段树将i~x-1置为0.将x置为res-val.(res=sum[i~x])
查询时直接query(x,x) O(nlog^2n)
法2:
用set存当前还能装水的碟子下标,第i个碟子装水时 直接模拟.二分找到下一个下标,若不能装满 则结束.
初始碟子为空,m个操作,op1:第x个碟子装p单位水,op2:询问第k个碟子有多少水.n,m<=2e5,a[i]<=1e9;
法1:
第i个碟子装水,二分最远能流到第x个,用线段树将i~x-1置为0.将x置为res-val.(res=sum[i~x])
查询时直接query(x,x) O(nlog^2n)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+20;
ll a[N];
struct node{
int l,r;
int mid()
{
return (l+r)>>1;
}
ll sum,lz;
}t[N<<2];
void push_up(int rt)
{
t[rt].sum=t[rt<<1].sum+t[rt<<1|1].sum;
}
void build(int rt,int l,int r)
{
t[rt].l=l,t[rt].r=r;
t[rt].lz=-1;
if(l==r)
{
t[rt].sum=a[l];
return;
}
int m=t[rt].mid();
build(rt<<1,l,m);
build(rt<<1|1,m+1,r);
push_up(rt);
}
void push_down(int rt)
{
if(t[rt].lz!=-1)
{
t[rt<<1].lz=t[rt<<1|1].lz=0;
t[rt<<1].sum=t[rt<<1|1].sum=0;
t[rt].lz=-1;
}
}
void update(int rt,int ql,int qr,int val)
{
int l=t[rt].l,r=t[rt].r;
if(ql<=l&&qr>=r)
{
t[rt].sum=val;
t[rt].lz=val;
return;
}
push_down(rt);
int m=t[rt].mid();
if(ql<=m)
update(rt<<1,ql,qr,val);
if(qr>m)
update(rt<<1|1,ql,qr,val);
push_up(rt);
}
ll query(int rt,int ql,int qr)
{
int l=t[rt].l,r=t[rt].r;
if(ql<=l&&qr>=r)
return t[rt].sum;
push_down(rt);
int m=t[rt].mid();
ll ans=0;
if(ql<=m)
ans+=query(rt<<1,ql,qr);
if(qr>m)
ans+=query(rt<<1|1,ql,qr);
return ans;
}
bool check(int l,int r,ll x)
{
ll res=query(1,l,r);
return res>=x;
}
int main()
{
int n;
while(cin>>n)
{
for(int i=1;i<=n;i++)
scanf("%I64d",&a[i]);
//n++,a[n]=2e16;
build(1,1,n);
int m;
scanf("%d",&m);
while(m--)
{
int op,p;
ll x;
scanf("%d",&op);
if(op==1)
{
scanf("%d%I64d",&p,&x);
ll l=p,r=n,pos=n+1;
while(l<=r)
{
ll mid=(l+r)>>1;
if(check(p,mid,x))
r=mid-1,pos=mid;
else
l=mid+1;
}
ll res;
if(pos<=n)
res=query(1,p,pos),update(1,pos,pos,res-x);
if(pos>p)
update(1,p,pos-1,0);
}
else
{
scanf("%I64d",&x);
printf("%I64d\n",a[x]-query(1,x,x));
}
}
}
return 0;
}
法2:
用set存当前还能装水的碟子下标,第i个碟子装水时 直接模拟.二分找到下一个下标,若不能装满 则结束.
若下一个被装满 在set中删除该下标 继续找下一个,该步骤总共不会超过nlogn次
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+20;
int a[N],b[N];
set<int> s;
int main()
{
int n,m;
while(cin>>n)
{
s.clear();
memset(b,0,sizeof(b));
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),s.insert(i);
cin>>m;
while(m--)
{
int op,pos,x;
set<int>::iterator it;
scanf("%d",&op);
if(op==1)
{
scanf("%d%d",&pos,&x);
while(x)
{
it=s.lower_bound(pos);
if(it==s.end())
break;
pos=*it;
if(b[pos]+x>a[pos])
{
x-=a[pos]-b[pos];
b[pos]=a[pos];
s.erase(it);
}
else
{
b[pos]+=x;
break;
}
}
}
else
{
scanf("%d",&pos);
printf("%d\n",b[pos]);
}
}
}
return 0;
}