1 条题解
-
0
自动搬运
来自洛谷,原作者为

wgyhm
CF不上GM不改搬运于
2025-08-24 22:47:54,当前版本为作者最后更新于2023-08-31 07:35:50,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
Description
https://www.luogu.com.cn/problem/P9388
Solution
观察到操作序列一定,操作顺序对答案并没有影响。
将答案拆为 ,只需要求出操作后的前缀和即可。
观察到对于一个前缀区间,操作的本质就是将当前操作的所有 和 扔到一个堆里,取最小的前 扔给后面。所以只需要快速找到前 小之和即可。对于序列和操作分别用主席树和权值线段树,查询两个一起跑。
没有卡常。
#define int long long #define maxn 500005 int n,m; int a[maxn],suf[maxn],root[maxn],rota,cnt; struct node { int ls,rs,sum,siz; } f[maxn*30]; int Update(int l,int r,int pre,int head) { int rt=++cnt; f[rt]=f[pre]; f[rt].siz++; f[rt].sum+=head; if (l==r) return rt; int mid=l+r>>1; if (head<=mid) f[rt].ls=Update(l,mid,f[rt].ls,head); else f[rt].rs=Update(mid+1,r,f[rt].rs,head); return rt; } void Update2(int l,int r,int &rt,int head) { if (!rt) rt=++cnt; f[rt].siz++,f[rt].sum+=head; if (l==r) return ; int mid=l+r>>1; if (head<=mid) Update2(l,mid,f[rt].ls,head); else Update2(mid+1,r,f[rt].rs,head); } int Query(int l,int r,int rt1,int rt2,int k) { if (l==r) return k*l; int mid=l+r>>1,siz=f[f[rt1].ls].siz+f[f[rt2].ls].siz; if (siz>=k) return Query(l,mid,f[rt1].ls,f[rt2].ls,k); else return f[f[rt1].ls].sum+f[f[rt2].ls].sum+Query(mid+1,r,f[rt1].rs,f[rt2].rs,k-siz); } signed main(void) { int i,x,l,r,sum=0; read(n); read(m); for (i=1; i<=n; i++) read(a[i]),suf[i]=suf[i-1]+a[i]; for (i=1; i<=n; i++) { root[i]=Update(1,n,root[i-1],a[i]); } for (i=1; i<=m; i++) { read(x);read(l);read(r);sum+=x; Update2(1,n,rota,x); int tmp1=suf[l-1]+sum-Query(1,n,root[l-1],rota,i); int tmp2=suf[r]+sum-Query(1,n,root[r],rota,i); printf("%lld\n",tmp2-tmp1); } return 0; }
- 1
信息
- ID
- 8806
- 时间
- 3000ms
- 内存
- 512MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者