首页 > 其他分享 >P6406 [COCI2014-2015#2] Norma 题解

P6406 [COCI2014-2015#2] Norma 题解

时间:2022-11-14 22:44:56浏览次数:71  
标签:min int 题解 Norma mn times max 2015 sum

前言

洛谷上很多大佬都写的 CDQ分治 的解法。但看了某篇大佬的线段树解法,受益匪浅,于是决定写一篇题解来记录一下这种解法。

前置知识:单调栈线段树


题目通道

题目描述

给定一个正整数序列 \(a_1,a_2,\cdots,a_n\) ,求

\[\sum_{i=1}^{n}\sum_{j=i}^{n}(j-i+1)\min(a_i,a_{i+1},\cdots,a_j)\max(a_i,a_{i+1},\cdots,a_j) \]

对于 \(100\%\) 的数据,\(1 \le n \leq 5\times 10^5\),\(1 \le a_i \le 10^8\)。

思路

我们这里定义 \(min_{l,r}\) 和 \(max_{l,r}\) 分别为 \(a_l,a_{l+1},a_{l+2},\cdots,a_r\) 的 最小值最大值

题目让求的是

\[\sum_{l=1}^{n}\sum_{r=l}^{n}(r-l+1)\times min_{l,r}\times max_{l,r}\\ =\sum_{l=1}^{n}\sum_{r=l}^{n}(r+1)\times min_{i,j}\times max_{i,j} - l\times min_{i,j}\times max_{i,j} \]

显然的,对于每个 \(r\) 做出的贡献为

\[(r+1)\times\sum_{l=1}^{r} min_{l,r}\times max_{l,r} \]

对于每个 \(l\) 做出的贡献为

\[-l\times \sum_{r=l}^{n} min_{l,r}\times max_{l,r} \]

这两个求法类似,这里就只讲 \(r\) 的解法。

假设现在已经有 \(r\) 这个右端点。

设 \(min(i)\) 和 \(max(i)\) 分别为 \(i\) 到 \(r\) 的区间最小值和区间最大值。

那么以 \(r\) 作为右端点做出的贡献就为

\[\sum_{i=1}^{r} min(i)\times max(i) \]

考虑快速维护 \(min(i)\) 和 \(max(i)\) 。

考虑右端点从 \(r-1\) 变为 \(r\) 的过程。设 \(a_{j}(j<r)\) 为从 \(r\) 左边第一个 小于等于 \(a_i\) 的值,那么 \(a_i\) 只会对 \(min(j\cdots i)\) 造成影响,\(a_i\) 对 \(max()\) 的贡献同理。

显然的对于维护左边第一个 小于等于大于等于 \(a_i\) 的值可以用 单调栈 做到总复杂度 \(O(n)\)。

再考虑用线段树维护以下信息

区间修改min(x)

区间修改max(x)

区间查询 \(\sum_{i=1}^r min(i)\times max(i)\)

这里的线段树维护信息和单调栈比较好写,就不细讲了

code

#include<bits/stdc++.h>
#define ll long long
#define mid ((l+r)>>1)
using namespace std;
const int N=5e5+3,p=1e9;
struct Val{
    int sa,sb,sm;
    Val(){sa=sb=sm=0;}
};
Val operator+(Val x,Val y){
    Val z;
    z.sa=(x.sa+y.sa)%p;
    z.sb=(x.sb+y.sb)%p;
    z.sm=(x.sm+y.sm)%p;
    return z;
}
struct node{
    int tga=-1,tgb=-1;
    Val v;
    void val(int ta,int tb,int l,int r){
        if(~ta){
            tga=ta;
            v.sa=(ta*1LL*(r-l+1))%p;
            v.sm=(ta*1LL*v.sb)%p;
        }
        if(~tb){
            tgb=tb;
            v.sb=(tb*1LL*(r-l+1))%p;
            v.sm=(tb*1LL*v.sa)%p;
        }
    }
}tr[(N<<2)];
void push_down(int x,int l,int r){
    tr[x<<1].val(tr[x].tga,tr[x].tgb,l,mid);
    tr[x<<1|1].val(tr[x].tga,tr[x].tgb,mid+1,r);
    tr[x].tga=tr[x].tgb=-1;
}
void push_up(int x)
    {tr[x].v=tr[x<<1].v+tr[x<<1|1].v;}
void change(int x,int l,int r,int ql,int qr,int ta,int tb){
    if(l>=ql&&r<=qr){tr[x].val(ta,tb,l,r);return;}
    if(l>qr||r<ql) return;
    push_down(x,l,r);
    change(x<<1,l,mid,ql,qr,ta,tb),
    change(x<<1|1,mid+1,r,ql,qr,ta,tb);
    push_up(x);
}
Val ask(int x,int l,int r,int ql,int qr){
    if(l>=ql&&r<=qr) return tr[x].v;
    if(l>qr||r<ql) return Val();
    push_down(x,l,r);
    return ask(x<<1,l,mid,l,r)+ask(x<<1|1,mid+1,r,l,r);
}
int a[N],n;
ll ans=0;
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    stack<int>mn,mx;
    for(int i=1;i<=n;i++){
        while(mx.size()&&a[mx.top()]<a[i]) mx.pop();
        if(mx.size()) change(1,1,n,mx.top()+1,i,a[i],-1);
        else change(1,1,n,1,i,a[i],-1);
        mx.push(i);
        while(mn.size()&&a[mn.top()]>a[i]) mn.pop();
        if(mn.size()) change(1,1,n,mn.top()+1,i,-1,a[i]);
        else change(1,1,n,1,i,-1,a[i]);
        mn.push(i);
        auto v=ask(1,1,n,1,i);
        ans=(ans+(v.sm*1LL*(i+1))%p)%p;
    }
    while(mn.size()) mn.pop();
    while(mx.size()) mx.pop();
    change(1,1,n,1,n,0,0);
    for(int i=n;i>=1;i--){
        while(mx.size()&&a[mx.top()]<a[i]) mx.pop();
        if(mx.size()) change(1,1,n,i,mx.top()-1,a[i],-1);
        else change(1,1,n,i,n,a[i],-1);
        mx.push(i);
        while(mn.size()&&a[mn.top()]>a[i]) mn.pop();
        if(mn.size()) change(1,1,n,i,mn.top()-1,-1,a[i]);
        else change(1,1,n,i,n,-1,a[i]);
        mn.push(i);
        auto v=ask(1,1,n,i,n);
        ans=(ans-(v.sm*1LL*i)%p)%p;
    }
    cout<<(ans%p+p)%p;
    return 0;
}

标签:min,int,题解,Norma,mn,times,max,2015,sum
From: https://www.cnblogs.com/I-am-yzh/p/16890772.html

相关文章

  • CF1743F Intersection and Union 题解
    更好体验线段的贡献不好统计,考虑统计每一个点在不同情况中的被覆盖次数,那么每个点的被覆盖次数总和即为答案。设\(f_{i,j,0/1}\)表示\(i\)点在扫描到线段\(j\)时是......
  • LG5283 [十二省联考 2019] 异或粽子 题解
    口胡一个异或经典问题LG5283[十二省联考2019]异或粽子给定一个长为\(n\)的序列,序列一段子区间\([l,r]\)的值为\([l,r]\)范围内所有数异或起来的值。现在求出前......
  • 题解 HDU4035 【Maze】
    postedon2022-08-1712:33:51|under题解|sourceproblemhttps://vjudge.net/problem/HDU-4035SHY在一棵树上随机游走,从根节点出发,每次有\(k_u\)的几率回到根节......
  • ARC 103 /\/\/\/ 题解
    前缀和一下,就好了#include<bits/stdc++.h>usingnamespacestd;typedefunsignedlonglongull;constintN=1e5+99;inta[N],odd[N],even[N];structcmp{ boolo......
  • CSP-S 2022 题解
    T1假期计划\(\ttloj3899\)/\(\ttuoj773\)首先数据规模是\(n\le2500\),提示我们用\(\mathcalO\left(n^2\right)\)的算法。既然是选择\(4\)个互不相同的点,不妨......
  • 题解:【ABC245F】Endless Walk
    题目链接本题解适合像我这样的不具备思维能力的选手。首先根据题意,一个点如果符合要求,那它必然在一个点数大于\(2\)的强联通分量里,因为如果只有一个点它就哪里都去不了......
  • Codeforces 722 F Cyclic Cipher 题解 (同余方程,two-pointers)
    题目链接前两天做过一个题意类似但做法不类似的题在这里首先做这道题需要一个结论:(一元)同余方程组有解的充要条件是方程组中的所有方程两两联立有解。证明两个同......
  • CF1650G 『Counting Shortcuts』 题解
    从洛谷博客那里搬过来的(图论专题本来打算先挑最简单的做,结果做了两个多小时(题意就是让你找从起点\(s\)到终点\(t\)的最短路以及次短路个数,本题次短路长度指的是最短......
  • Codeforces 833 题解
    A\(n\)是奇数时恰好可以用完,\(n\)是偶数时多出来的一块没用,所以直接输出\((n+1)/2\)即可。B每个字符出现次数都小于等于字符总数,令\(\Sigma\)是字符集大小,那显然......
  • CF1292E Rin and The Unknown Flower 题解
    IO交互题fflush(stdout)害人不浅!!1注意到如果我们发起询问C和O就可以花费2的代价知道整个串,不过代价过高,所以我们考虑减小点代价。考虑发起询问CO,CH,CC,这样我......