概述
题目链接
题目大意: 有一个博客, 初始分数为$0$, 有$n$个人, 第$i$个人有一个期望值$a_i$,
如果第$i$个人浏览博客时,博客赞数高于$a_i$博客分数$-1$, 低于$+1$, 相等不变,
对于每个$i$, 求出$[1,i]$的人按任意顺序浏览博客后最大分数.
题解:
首先, 用贪心可以知道所有人按期望升序排列, 最后得分一定最大
由于期望有负数, 博客分数一定是先减后增的, 然后对这两段分类讨论
对于递减的段, 最后分数为递增递减的临界值
假设临界值为$x$, 设比$x$小的数的个数为$cnt_x$
可以发现$x$是第一个满足 $cnt_x+x>=0$ 的$x$
比方说排序后序列为$-10,-10,-10,-6,-2,-1$ 那么$x$就为$-4$
权值线段树上二分即可求出$x$ (初值设为$x$, 转为二分第一个$>=0$的数)
在考虑递增区间, 假设当前一共有$r$个数
有转移方程 $f_i=min(a_i,f_{i-1}+1),$ $f$为得分, $a$为排序后数组
可以得到$f_r=min(a_r,a_{r-1}+1,a_{r-2}+2,...,a_{l}+r-l,x+(r-x))$, $a_{l}$为第一个比$x$大的数
用权值线段树维护最小值即可
1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #define REP(i,a,n) for(int i=a;i<=n;++i) 5 #define mid ((l+r)>>1) 6 #define lc (o<<1) 7 #define rc (lc|1) 8 #define ls lc,l,mid 9 #define rs rc,mid+1,r 10 using namespace std; 11 12 const int N = 5e5+10, INF = 0x3f3f3f3f; 13 14 int n, m, ans; 15 struct _ { 16 int mx,tag; 17 void upd(int x) { 18 mx+=x,tag+=x; 19 } 20 } v1[N<<2], v2[N<<3]; 21 22 //v1维护的递减区间 23 //v2维护递增区间 24 25 void pd(_ *v, int o) { 26 if (v[o].tag) { 27 v[lc].upd(v[o].tag); 28 v[rc].upd(v[o].tag); 29 v[o].tag=0; 30 } 31 } 32 33 void add1(int o, int l, int r, int ql, int qr) { 34 if (ql<=l&&r<=qr) return v1[o].upd(1); 35 pd(v1,o); 36 if (mid>=ql) add1(ls,ql,qr); 37 if (mid<qr) add1(rs,ql,qr); 38 v1[o].mx=max(v1[lc].mx,v1[rc].mx); 39 } 40 41 void add2(int o, int l, int r, int ql, int qr) { 42 if (ql<=l&&r<=qr) return v2[o].upd(1); 43 pd(v2,o); 44 if (mid>=ql) add2(ls,ql,qr); 45 if (mid<qr) add2(rs,ql,qr); 46 v2[o].mx=min(v2[lc].mx,v2[rc].mx); 47 } 48 49 int qry1(int o, int l, int r) { 50 if (l==r) return l; 51 pd(v1,o); 52 if (v1[lc].mx>=0) return qry1(ls); 53 return qry1(rs); 54 } 55 56 void qry2(int o, int l, int r, int ql, int qr) { 57 if (v2[o].mx>=ans) return; 58 if (ql<=l&&r<=qr) return ans=min(ans,v2[o].mx),void(); 59 pd(v2,o); 60 if (mid>=ql) qry2(ls,ql,qr); 61 if (mid<qr) qry2(rs,ql,qr); 62 } 63 64 void build1(int o, int l, int r) { 65 if (l==r) return v1[o].mx=l,void(); 66 build1(ls),build1(rs); 67 v1[o].mx=max(v1[lc].mx,v1[rc].mx); 68 } 69 70 void build2(int o, int l, int r) { 71 if (l==r) return v2[o].mx=l,void(); 72 build2(ls),build2(rs); 73 v2[o].mx=min(v2[lc].mx,v2[rc].mx); 74 } 75 76 int main() { 77 scanf("%d", &n); 78 build1(1,-N,0); 79 build2(1,-N,N); 80 REP(i,1,n) { 81 int k; 82 scanf("%d", &k); 83 if (k<0) add1(1,-N,0,k,N); 84 add2(1,-N,N,-N,k-1); 85 int x = qry1(1,-N,0); 86 ans = INF, qry2(1,-N,N,x,N); 87 printf("%dn", ans); 88 } 89 }
转载于:https://www.cnblogs.com/uid001/p/10248923.html
最后
以上就是虚拟钢铁侠为你收集整理的Blog Post Rating CodeForces - 806E (线段树二分)的全部内容,希望文章能够帮你解决Blog Post Rating CodeForces - 806E (线段树二分)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复