• CF773E Blog Post Rating


    题意:有一篇博客。一共有n个人,心中有他们期望该博客得到的赞数a[i]。当某个时刻该博客的获赞数<a[i],则该人会使得赞数+1,当赞数>a[i],该人会使得赞数-1,当赞数=a[i],不做任何改变。

    对于1<=k<=n,询问1~k个人按一定的顺序给该博客从0开始点赞或点踩,该博客的最大获赞数。

    -1e5<=a[i]<=1e5,n<=1e5。

    标程:

     1 #include<bits/stdc++.h>
     2 #define mid ((l+r)>>1)
     3 using namespace std;
     4 const int N=500002;
     5 const int inf=0x3f3f3f3f;
     6 int tag1[N<<3],tag2[N<<3],Max[N<<3],Min[N<<3],n,ax;
     7 
     8 void build1(int k,int l,int r)
     9 {
    10     if (l==r) {Max[k]=l;return;}
    11     build1(k<<1,l,mid);build1(k<<1|1,mid+1,r);
    12     Max[k]=max(Max[k<<1],Max[k<<1|1]);
    13 }
    14 void build2(int k,int l,int r)
    15 {
    16     if (l==r) {Min[k]=l;return;}
    17     build2(k<<1,l,mid);build2(k<<1|1,mid+1,r);
    18     Min[k]=min(Min[k<<1],Min[k<<1|1]);
    19 }
    20 void down1(int k)
    21 {
    22     if (tag1[k])
    23     {
    24         tag1[k<<1]+=tag1[k],tag1[k<<1|1]+=tag1[k];
    25         Max[k<<1]+=tag1[k],Max[k<<1|1]+=tag1[k];
    26         tag1[k]=0;
    27     }
    28 }
    29 void down2(int k)
    30 {
    31     if (tag2[k])
    32     {
    33         tag2[k<<1]+=tag2[k],tag2[k<<1|1]+=tag2[k];
    34         Min[k<<1]+=tag2[k],Min[k<<1|1]+=tag2[k];
    35         tag2[k]=0;
    36     }
    37 }
    38 void add1(int k,int l,int r,int x)
    39 {
    40    if (x<=l) {tag1[k]++;Max[k]++;return;}
    41    down1(k);
    42    if (x<=mid) add1(k<<1,l,mid,x);
    43    add1(k<<1|1,mid+1,r,x);
    44    Max[k]=max(Max[k<<1],Max[k<<1|1]);
    45 }
    46 void add2(int k,int l,int r,int x)
    47 {
    48     if (r<=x) {tag2[k]++;Min[k]++;return;}
    49     down2(k);
    50     if (x>mid) add2(k<<1|1,mid+1,r,x);
    51     add2(k<<1,l,mid,x);
    52     Min[k]=min(Min[k<<1],Min[k<<1|1]);
    53 }
    54 int qry1(int k,int l,int r)//找到恰好为0的位置 
    55 {
    56     if (l==r) return l;
    57     down1(k);
    58     if (Max[k<<1]>=0) return qry1(k<<1,l,mid);
    59     else return qry1(k<<1|1,mid+1,r);
    60 }
    61 int qry2(int k,int l,int r,int x)
    62 {
    63     if (x<=l) return Min[k];
    64     down2(k); int res=inf;
    65     if (x<=mid) res=min(res,qry2(k<<1,l,mid,x));
    66     res=min(res,qry2(k<<1|1,mid+1,r,x));
    67     return res;
    68 }
    69 int main()
    70 {
    71     build1(1,-N,0);
    72     build2(1,-N,N);
    73     scanf("%d",&n);
    74     for (int i=1;i<=n;i++)
    75     {
    76         scanf("%d",&ax);
    77         if (ax<0) add1(1,-N,0,ax);
    78         add2(1,-N,N,ax-1);
    79         int l=qry1(1,-N,0);
    80         printf("%d
    ",qry2(1,-N,N,l));
    81     }
    82     return 0;
    83 }

    易错点:1.add1前缀++时,最后一个位置是不加的,所以应该从ax-1开始。

    题解:线段树优化dp展开

    发现一定是升序过来给赞是最优的,而这样一定存在一个分界点,该点之前x--,该点之后x单调不减。具体地,当a[x]<=-x时,x=x-1。我们设a[x]=-x的点为分界点。

    之后的单调不减怎么求答案?设f[i]为第i个人点赞后,该博客的获赞数。f[i]=min(f[i-1]+1,a[i])。

    展开:设分界点为x,分界点右边的第一个人为第l个,右端点为r,则f[r]=min(x+(r-l+1),a[l]+r-l,...,a[r-1]+1,a[r])。也可以用线段树优化掉。

    开两棵权值线段树,一棵用来寻找分界点,维护a[x]+x的值,插入时后缀区间+1,查询时求a[x]=x的点。一棵用来维护f数组,插入时前缀区间+1(不包括右端点),查询时求后缀最小值。

    不管是否实际加入元素,权值线段树的区间都是整体加,因为有单调性不会冲突。

  • 相关阅读:
    uniapp 画圆形或多边形雷达图
    uniApp开发之公用配置文件common.js
    FastAdmin 表格排序
    fastadmin SelectPage field显示多个字段
    PHP装饰器模式
    PHP原型模式,(理解:创建并初始化对象,再复制一个对象避免重复初始化)
    PHP设计模式-观察者模式
    为什么 echo 3 . print(2) . print(4) . 5 . 'c'的结果是45c2131
    PHP数组式访问接口ArrayAccess用法分析
    浏览器兼容性问题总结
  • 原文地址:https://www.cnblogs.com/Scx117/p/9087455.html
Copyright © 2020-2023  润新知