• bzoj4826[hnoi2017]影魔


    题意:每次询问一个区间[l,r],问[l,r]中的每一对(i,j)能够贡献多少总加成?给定序列a是1~n的一个排列,也就是a[i]两两不同。

    设z=max{a[i+1],a[i+2],...,a[j-1]},若z<min(a[i],a[j]),加成p1;若min(a[i],a[j])<z<max(a[i],a[j]),加成p2。n<=20W。

    标程:

     1 #include<bits/stdc++.h>
     2 #define mid ((l+r)>>1)
     3 #define P pair<int,ll>
     4 #define fir first
     5 #define sec second
     6 using namespace std;
     7 typedef long long ll;
     8 int read()
     9 {
    10    int x=0,f=1;char ch=getchar();
    11    while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
    12    while (ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    13    return x*f;
    14 }
    15 const int N=200005;
    16 int rt1[N],rt2[N],sc,num[N*40],ls[N*40],rs[N*40],n,m,lf[N],rg[N],p1,p2,top,a[N],q[N];
    17 ll sum[N*40];
    18 P operator + (P a,P b) {return P(a.fir+b.fir,a.sec+b.sec);}
    19 void ins(int &k,int pk,int l,int r,int x)
    20 {
    21     k=++sc;ls[k]=ls[pk];rs[k]=rs[pk];
    22     if (l==r) {sum[k]=sum[pk]+x;num[k]=num[pk]+1;return;}
    23     if (x<=mid) ins(ls[k],ls[pk],l,mid,x);
    24     else ins(rs[k],rs[pk],mid+1,r,x);
    25     sum[k]=sum[ls[k]]+sum[rs[k]];
    26     num[k]=num[ls[k]]+num[rs[k]];
    27 }
    28 P qry(int k1,int k2,int l,int r,int L,int R)
    29 {
    30     if (!k1) return P(0,0);//if(!k2)跳出P(num[k1],sum[k1])是不行的,考虑区间要在[L,R]内 
    31     if (L<=l&&r<=R) return P(num[k1]-num[k2],sum[k1]-sum[k2]);
    32     P res=P(0,0);
    33     if (L<=mid) res=res+qry(ls[k1],ls[k2],l,mid,L,R);
    34     if (R>mid) res=res+qry(rs[k1],rs[k2],mid+1,r,L,R);
    35     return res;
    36 }
    37 int main()
    38 {
    39     n=read();m=read();p1=read();p2=read();
    40     for (int i=1;i<=n;i++) a[i]=read();
    41     for (int i=1;i<=n;i++)
    42     {
    43         while (top>=1&&a[i]>a[q[top]]) top--;
    44         lf[i]=q[top];q[++top]=i;
    45     }
    46     q[top=0]=n+1;
    47     for (int i=n;i>=1;i--)
    48     {
    49         while (top>=1&&a[i]>a[q[top]]) top--;
    50         rg[i]=q[top];q[++top]=i;
    51     }
    52     for (int i=1;i<=n;i++) 
    53         ins(rt1[i],rt1[i-1],0,n+1,lf[i]),ins(rt2[i],rt2[i-1],0,n+1,rg[i]);
    54     while (m--)
    55     {
    56         int l,r;
    57         l=read();r=read();
    58         P z1=qry(rt1[r],rt1[l-1],0,n+1,l,n);
    59         P z2=qry(rt2[r],rt2[l-1],0,n+1,1,r);
    60         ll x1=z1.fir+z2.fir;
    61         ll x2=z2.sec-z1.sec+(ll)(r+1)*(r-l+1-z2.fir)-(ll)(l-1)*(r-l+1-z1.fir)-2*(r-l+1);
    62         printf("%lld
    ",(ll)p1*x1+(ll)p2*(x2-x1));
    63     }
    64    return 0;
    65 }
    View Code

    题解:计数+主席树

    一开始卡在没有意识到计数时可以通过设置大小关系做到不重,一个区间只用统计到一个端点。

    设[l,r]区间中满足限制1的有x1个,设满足z<max(a[i],a[j])限制2的有x2个(这样转化比较好求)。最后答案是x1*p1+(x2-x1)*p2。

    考虑构造统计方式:对于每一个位置求出lf[i]和rg[i]表示左右离i位置最近的比它大的位置。

    限制1:设i位置为较小端点,满足条件的端点只有lf[i]和rg[i]。式子:$sum_{i=l}^{r}[lf[i]>=l]+[rg[i]<=r]$。

    限制2:设i位置为较大端点,满足条件的是(lf[i],i)∪(i,rg[i])。式子:$sum_{i=l}^{r}(min(rg[i],r+1)-max(lf[i],l-1)-2)$。权值主席树计算。

  • 相关阅读:
    [转]为什么udp为什么不能发送大于1472字节数据
    曾经的那些入过的坑 内网中部署bcos
    安装FISCO-BCOS的那些坑
    springcloud基础入门
    BCOS常见的问题
    软件测试工程师必须要知道的9点
    十款APP开发框架
    Thinkphp开源框架如何使用?
    软件测试工程师面试必须要注意的7点
    一个APP开发有那么难吗?
  • 原文地址:https://www.cnblogs.com/Scx117/p/9162659.html
Copyright © 2020-2023  润新知