昨天晚上做完4题还有30分钟,感觉太晚了就没继续写,不过看了下E题感觉是一个线段树题目,今天中午看了看发现就是一个线段树上递归的询问问题,不过我之前没写过但是靠着日益强大的乱写能力竟然水出来了~~
E. Greedy Shopping
不难知道操作1并不改变原数组不升序的性质即非严格单调递减的性质永远存在。
操作一:在线段树上二分第一个小于y的数的位置pos,然后区间修改即可[pos→x][pos\to x][pos→x]
操作二:维护一个区间最小值和区间和,然后递归乱搞,由于每次能买则买先往左子树递归,然后记录一下左子树的花费,再往右子树递归这时候剩余的钱要减去左子树的花费,全局变量记录答案。
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<set>
#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<random>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_map>
#include<unordered_set>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=400010;
ll a[N];
int n,q;
struct node
{int l,r;ll sum,mn;ll lazy;
}tree[N*4];
void pushup(int u)
{tree[u].sum=tree[u<<1].sum+tree[u<<1|1].sum;tree[u].mn=min(tree[u<<1].mn,tree[u<<1|1].mn);
}
void pushdown(int u)
{if(!tree[u].lazy)return;tree[u<<1].sum=(tree[u<<1].r-tree[u<<1].l+1)*tree[u].lazy;tree[u<<1|1].sum=(tree[u<<1|1].r-tree[u<<1|1].l+1)*tree[u].lazy;tree[u<<1].mn=tree[u<<1|1].mn=tree[u].lazy;tree[u<<1].lazy=tree[u<<1|1].lazy=tree[u].lazy;tree[u].lazy=0;
}
void build(int u,int l,int r)
{tree[u]={l,r};if(l==r) {tree[u].sum=tree[u].mn=a[l];return;}int mid=l+r>>1;build(u<<1,l,mid),build(u<<1|1,mid+1,r);pushup(u);
}
void modify(int u,int l,int r,ll val)
{if(tree[u].l>=l&&tree[u].r<=r){tree[u].lazy=tree[u].mn=val;tree[u].sum=(tree[u].r-tree[u].l+1)*val;return;}pushdown(u);int mid=tree[u].l+tree[u].r>>1;if(l<=mid) modify(u<<1,l,r,val);if(r>mid) modify(u<<1|1,l,r,val);pushup(u);
}
int findmn(int u,ll val)
{if(tree[u].l==tree[u].r) return tree[u].l;pushdown(u);if(tree[u<<1].mn>=val) return findmn(u<<1|1,val);else return findmn(u<<1,val);
}
int ans;
int calc(int u,int l,int r,ll now)
{if(tree[u].r<l||tree[u].l>r||!now) return 0;if(tree[u].l>=l&&tree[u].r<=r){if(tree[u].sum<=now){ans+=tree[u].r-tree[u].l+1;return tree[u].sum;}}ll w=0;pushdown(u);int mid=tree[u].l+tree[u].r>>1;if(l<=mid&&tree[u<<1].mn<=now) w+=calc(u<<1,l,r,now);if(r>mid) w+=calc(u<<1|1,l,r,now-w);return w;
}
int main()
{IO;int T=1;//cin>>T;while(T--){cin>>n>>q;for(int i=1;i<=n;i++) cin>>a[i];build(1,1,n+1);while(q--){int op,x,y;cin>>op>>x>>y;if(op==1){int pos=findmn(1,y);if(pos<=x) modify(1,pos,x,y); }else{ans=0;calc(1,x,n,y);cout<<ans<<'\n';}}}return 0;
}
此代码必须在多开一倍空间,要不然calc函数越界?我也不知道为啥很迷
要加哟哦~