Codeforces 题目传送门 & 洛谷题目传送门

一道线段树的套路题(似乎 ycx 会做这道题?orzorz!!11)

首先考虑什么样的 \(x\) 是“不合适”的,我们假设 \(a_1<a_2<a_3<\cdots<a_{n-1}<a_n\),显然如果 \(\exist k\) 使得 \(a_1+a_2+\cdots+a_k\le x<a_{n-k+1}+a_{n-k+2}+\cdots+a_{n}\),那么 \(x\) 就是不合法的。也就是说所有 \(x\) 可取的数组成的集合为 \(n\) 个形如 \([a_1+a_2+\cdots+a_k,a_{n-k+1}+a_{n-k+2}+\cdots+a_{n})\) 的区间的并,而我们要求的就是这个并集的大小。

直接求并集似乎不是特别容易,因为可能会存在区间有交,贡献不太容易直接计算(当然如果硬要算也是可以算的,不过分类讨论应该会下面的解法稍微复杂些)。我们不妨考虑正难则反,拿总个数减去“合适”的 \(x\) 的个数,记 \(A=\sum\limits_{i=1}^na_i\),那么在区间 \([0,A)\) 中,\(x\) 为“合适”的值当且仅当 \(\exist k\in[0,n-1]\) 满足 \(a_{n-k+1}+a_{n-k+2}+\cdots+a_n\le x<a_1+a_2+\cdots+a_k+a_{k+1}\),而显然这样的 \(n\) 个区间是不存在交集的,因此“合适的” \(x\) 的个数可以直接通过将这 \(n\) 个区间的长度相加求出,即 \(\sum\limits_{k=0}^{n-1}\max((a_1+a_2+\cdots+a_k+a_{k+1})-(a_{n-k+1}+a_{n-k+2}+\cdots+a_n),0)\)(因为可能存在区间为空,因此要对 \(0\) 取 \(\max\))。我们记 \(f(k)=(a_1+a_2+\cdots+a_k+a_{k+1})-(a_{n-k+1}+a_{n-k+2}+\cdots+a_n)\),那么 \(ans=\sum\limits_{k=0}^{n-1}\max(f(k),0)\),这边带个 \(\max\),不好直接算出,因此我们不妨来探究下 \(f\) 函数有什么性质,很容易发现 \(f(k)\) 满足以下两个性质:

  • \(f(k)=f(n-1-k)\)(提示:在左右两个括号同时加上 \(a_{k+2}+a_{k+3}+\cdots+a_{n-k}\))
  • \(\forall x<y\le\dfrac{n-1}{2}\),\(f(x)>f(y)\)(提示:对于 \(k<\dfrac{n-1}{2}\),\(f(k)-f(k-1)=a_{k+1}-a_{n-k+1}<0\))

第一个性质告诉我们可以计算前一半(\(k\le\dfrac{n-1}{2}\))的答案,然后乘个 \(2\),如果 \(n\) 是奇数再减去 \(\max(f(\dfrac{n-1}{2}),0)\) 即可计算求得最终答案。第二个性质告诉我们满足 \(f(k)>0,k<\dfrac{n-1}{2}\) 的 \(k\) 是一段前缀,可二分找到最大的满足 \(f(l)>0\) 的 \(l\),计算 \(\sum\limits_{i=0}^lf(i)\),这样就可以不带 \(\max\),直接计算了。

最后是就是怎样计算 \(f(l)\) 和一段前缀的 \(f(l)\) 的问题。考虑将 \(a\) 离散化并建权值线段树,然后可在权值线段树上二分在对数时间内找到全局第 \(k\) 大的值以及前 \(k\) 大的和。而 \(\sum\limits_{i=0}^lf(i)=\sum\limits_{i=0}^l(\sum\limits_{j=1}^{i+1}a_j-\sum\limits_{j=n-i+1}^na_j)=\sum\limits_{j=1}^{l+1}a_j(l+1-j)-\sum\limits_{n-l+1}a_j(j-n+l)\),在线段树上额外维护 \(\sum\limits_{i}a_ii\) 即可,这东西也可在 \(\log n\) 时间内求出。时间复杂度 \(n\log^2n\),因为在找最大的 \(f(l)>0\) 的 \(l\) 过程中需二分,可能可以用线段树二分等技巧把那个 \(\log\) 去掉,不过没想了(

最后,有人可能会担心运算过程中爆 long long,事实上虽然 \(\sum\limits_{i}a_ii\) 可能会爆 long long,但是答案是在 long long 范围内的,因此可以理解为系统像字符串哈希一样自动对 \(2^{64}\) 取模,而最后运算结果 \(<2^{64}\),因此取模得到的结果就是它本身,故直接用 long long 存是不会出问题的。

const int MAXN=2e5;
int n,qu,cnt=0,num=0;
ll key[MAXN*2+5],uni[MAXN*2+5],a[MAXN+5],tot=0;
struct event{int opt;ll x;} q[MAXN+5];
struct node{int l,r,cnt;ll sum,sum_i;} s[MAXN*8+5];
void build(int k,int l,int r){
s[k].l=l;s[k].r=r;if(l==r) return;
int mid=l+r>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);
}
void pushup(int k){
s[k].cnt=s[k<<1].cnt+s[k<<1|1].cnt;s[k].sum=s[k<<1].sum+s[k<<1|1].sum;
s[k].sum_i=s[k<<1].sum_i+s[k<<1|1].sum_i+s[k<<1|1].sum*s[k<<1].cnt;
}
void modify(int k,int p,int x){
if(s[k].l==s[k].r){
s[k].cnt+=x;s[k].sum+=x*uni[p];
s[k].sum_i=1ll*s[k].cnt*(s[k].cnt+1)/2*uni[p];
return;
} int mid=s[k].l+s[k].r>>1;
if(p<=mid) modify(k<<1,p,x);
else modify(k<<1|1,p,x);
pushup(k);
}
pair<ll,ll> getxth(int k,int x){
if(s[k].l==s[k].r){return mp(1ll*x*uni[s[k].l],1ll*x*(x+1)/2*uni[s[k].l]);}
if(x<=s[k<<1].cnt) return getxth(k<<1,x);
else{
pair<ll,ll> ss=getxth(k<<1|1,x-s[k<<1].cnt);
return mp(ss.fi+s[k<<1].sum,ss.se+s[k<<1].sum_i+ss.fi*s[k<<1].cnt);
}
}
ll getf(int k){
pair<ll,ll> s1=getxth(1,k+1),s2=getxth(1,n-k);
return s1.fi-(s[1].sum-s2.fi);
}
ll getans(){
if(!n) return 0;
int l=0,r=(n-1)/2,p=(n-1)/2+1;
while(l<=r){
int mid=l+r>>1;
if(getf(mid)<=0) p=mid,r=mid-1;
else l=mid+1;
} p--;//printf("%d\n",p);
pair<ll,ll> s1=getxth(1,p+1),s2=getxth(1,n-p);
s2.fi=s[1].sum-s2.fi;s2.se=s[1].sum_i-s2.se;
// printf("%lld %lld %lld %lld\n",s1.fi,s1.se,s2.fi,s2.se);
ll sum=s1.fi*(p+2)-s1.se-s2.se+s2.fi*(n-p);
sum=sum*2;if((n&1)) sum-=max(getf((n-1)/2),0ll);
return tot-sum;
}
int main(){
scanf("%d%d",&n,&qu);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]),key[++cnt]=a[i],tot+=a[i];
for(int i=1;i<=qu;i++){scanf("%d%lld",&q[i].opt,&q[i].x);key[++cnt]=q[i].x;}
sort(key+1,key+cnt+1);
for(int i=1;i<=cnt;i++) if(key[i]^key[i-1]) uni[++num]=key[i];
for(int i=1;i<=n;i++) a[i]=lower_bound(uni+1,uni+num+1,a[i])-uni;
for(int i=1;i<=qu;i++) q[i].x=lower_bound(uni+1,uni+num+1,q[i].x)-uni;
build(1,1,num);for(int i=1;i<=n;i++) modify(1,a[i],1);
printf("%lld\n",getans());
for(int i=1;i<=qu;i++){
if(q[i].opt==1) modify(1,q[i].x,1),++n,tot+=uni[q[i].x];
else modify(1,q[i].x,-1),--n,tot-=uni[q[i].x];
printf("%lld\n",getans());
}
return 0;
}

Codeforces 1500E - Subset Trick(线段树)的更多相关文章

  1. Buses and People CodeForces 160E 三维偏序+线段树

    Buses and People CodeForces 160E 三维偏序+线段树 题意 给定 N 个三元组 (a,b,c),现有 M 个询问,每个询问给定一个三元组 (a',b',c'),求满足 a ...

  2. CodeForces 877E DFS序+线段树

    CodeForces 877E DFS序+线段树 题意 就是树上有n个点,然后每个点都有一盏灯,给出初始的状态,1表示亮,0表示不亮,然后有两种操作,第一种是get x,表示你需要输出x的子树和x本身 ...

  3. [Codeforces 1197E]Culture Code(线段树优化建图+DAG上最短路)

    [Codeforces 1197E]Culture Code(线段树优化建图+DAG上最短路) 题面 有n个空心物品,每个物品有外部体积\(out_i\)和内部体积\(in_i\),如果\(in_i& ...

  4. [Codeforces 1199D]Welfare State(线段树)

    [Codeforces 1199D]Welfare State(线段树) 题面 给出一个长度为n的序列,有q次操作,操作有2种 1.单点修改,把\(a_x\)修改成y 2.区间修改,把序列中值< ...

  5. [Codeforces 316E3]Summer Homework(线段树+斐波那契数列)

    [Codeforces 316E3]Summer Homework(线段树+斐波那契数列) 顺便安利一下这个博客,给了我很大启发(https://gaisaiyuno.github.io/) 题面 有 ...

  6. Codeforces Gym 100231B Intervals 线段树+二分+贪心

    Intervals 题目连接: http://codeforces.com/gym/100231/attachments Description 给你n个区间,告诉你每个区间内都有ci个数 然后你需要 ...

  7. Codeforces 482B Interesting Array(线段树)

    题目链接:Codeforces 482B Interesting Array 题目大意:给定一个长度为N的数组,如今有M个限制,每一个限制有l,r,q,表示从a[l]~a[r]取且后的数一定为q,问是 ...

  8. codeforces 383C Propagating tree 线段树

    http://codeforces.com/problemset/problem/383/C 题目就是说,  给一棵树,将一个节点的值+val, 那么它的子节点都会-val, 子节点的子节点+val. ...

  9. CodeForces 228D. Zigzag(线段树暴力)

    D. Zigzag time limit per test 3 seconds memory limit per test 256 megabytes input standard input out ...

随机推荐

  1. 【c++ Prime 学习笔记】第5章 语句

    C++提供了一组控制流语句,包括条件执行语句.循环语句.跳转语句. 5.1 简单语句 空语句 ; ,最简单的语句 别漏写分号,也别多写 while(cin>>s && s! ...

  2. LeetCode:堆专题

    堆专题 参考了力扣加加对与堆专题的讲解,刷了些 leetcode 题,在此做一些记录,不然没几天就忘光光了 力扣加加-堆专题(上) 力扣加加-堆专题(下) 总结 优先队列 // 1.java中有优先队 ...

  3. Scrum Meeting 0529

    零.说明 日期:2021-5-29 任务:简要汇报七日内已完成任务,计划后两日完成任务 一.进度情况 组员 负责 七日内已完成的任务 后两日计划完成的任务 困难 qsy PM&前端 完成后端管 ...

  4. 【二食堂】Beta - Scrum Meeting 12

    Scrum Meeting 12 例会时间:5.27 20:00~20:10 进度情况 组员 当前进度 今日任务 李健 1. 知识图谱导出功能完成 issue 1. 继续完成文本保存的工作 issue ...

  5. BUAA 2020 软件工程 结对项目作业

    Author: 17373051 郭骏 3.28添加:4.计算模块接口的设计与实现过程部分,PairCore实现的细节 项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) ...

  6. spring session实现session统一管理(jdbc实现)

    最近在看一些关于spring session 的知识,特做一个笔记记录一下. 在项目中经常会遇到这么一种情况,同一个web项目有时需要部署多份,然后使用nginx实现负载均衡,那么遇到的问题就是,部署 ...

  7. 021中国大学生程序设计竞赛(CCPC)- 压力测试赛题解

    A.Matrix 挺狗的一道题,从开始冲到最后都没冲出来,都没啥思路. 其实分开考虑每个数的贡献,这个想法也存在过,就是不知道该怎么计算,我们考虑我们单独考虑一个数字\(i(1\leq i\leq n ...

  8. laravel路由导出和参数加密

    路由导出 代码位置:\vendor\laravel\framework\src\Illuminate\Foundation\Console\RouteListCommand.php protected ...

  9. httprunner3源码解读(4)parser.py

    源码结构目录 可以看到此模块定义了4个属性和12个函数,我们依次来讲解 属性源码分析 # 匹配http://或https:// absolute_http_url_regexp = re.compil ...

  10. webpack 之js兼容性处理

    webpack 之js兼容性处理 // 用来拼接绝对路径的方法 const {resolve} = require('path') const HtmlWebpackPlugin = require( ...