题意

给定一个长度为 \(n\) 的序列 \(\{a_i\}\)。你需要从该序列中选出两个非空的子段,这两个子段满足

  • 两个子段非包含关系。
  • 两个子段存在交。
  • 位于两个子段交中的元素在每个子段中只能出现一次。

求共有多少种不同的子段选择方案。输出总方案数对 \(10^9 + 7\) 取模后的结果。

需要注意的是,选择子段 \([a, b]\)、\([c, d]\) 与选择子段 \([c, d]\)、\([a, b]\) 被视为是相同的两种方案。

\(1 \leq n \leq 10^5, -10^9 \leq a_i \leq 10^9\)。

分析

  • 考虑枚举一个区间 \([b,c]\) 作为交,记录 \(L_i,R_i\) 表示距离 \(i\) 最近的和 \(i\) 颜色相同的位置。

  • 有: \(a\in[\max\limits_{i=b}^c{L_i},b),d\in(c,\min\limits_{i=b}^c{R_i}]\)。

  • 记录可以取到的左端点的最小值(满足区间中不存在两个相同的数) \(pos\) 。 \(mi, mx\) 分别表示 \([j,i]\) 中 \(R\) 的极小值和 \(L\) 的极大值。

  • 考虑从左到右枚举交区间的右端点 \(i\) ,用单调栈维护每个位置的 \(mi, mx\) 。容易得到以 \(i\) 为交区间的右端点的方案数为 \(\sum_{j=pos}^i(mi_j-i)(j-mx_j)​\),拆开然后用线段树分别维护。

  • 总时间复杂度为 \(O(nlogn)\)。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define go(u) for(int i = head[u], v = e[i].to; i; i=e[i].lst, v=e[i].to)
#define rep(i, a, b) for(int i = a; i <= b; ++i)
#define pb push_back
#define re(x) memset(x, 0, sizeof x)
inline int gi() {
int x = 0,f = 1;
char ch = getchar();
while(!isdigit(ch)) { if(ch == '-') f = -1; ch = getchar();}
while(isdigit(ch)) { x = (x << 3) + (x << 1) + ch - 48; ch = getchar();}
return x * f;
}
template <typename T> inline void Max(T &a, T b){if(a < b) a = b;}
template <typename T> inline void Min(T &a, T b){if(a > b) a = b;}
const int N = 1e5 + 7, mod = 1e9 + 7;
int n, vc;
LL ans;
int lst[N], L[N], R[N], V[N], a[N];
int st1[N], st2[N], tp1, tp2;
#define Ls o << 1
#define Rs (o << 1 | 1)
LL s1(int n) {
return 1ll * n * (n + 1) / 2;
}
LL ami[N << 2], amx[N << 2];
struct data {
LL mi, mx, smi, tm;
data operator +(const data &rhs) const {
return (data){ (mi + rhs.mi) % mod, (mx + rhs.mx) % mod, (smi + rhs.smi) % mod, (tm + rhs.tm) % mod};
}
}t[N << 2];
void add(LL &a, LL b) {
a += b;if(a >= mod) a -= mod;
}
void stmi(int l, int r, int o, int v) {
add(ami[o], v);
add(t[o].tm, 1ll * v * t[o].mx % mod);
add(t[o].mi, 1ll * (r - l + 1) * v % mod);
add(t[o].smi, (s1(r) - s1(l - 1)) % mod * v % mod);
}
void stmx(int l, int r, int o, int v) {
add(amx[o], v);
add(t[o].tm, 1ll * v * t[o].mi % mod);
add(t[o].mx, 1ll * (r - l + 1) * v % mod);
}
void pushdown(int l, int r, int o) {
int mid = l + r >> 1;
if(ami[o]) {
stmi(l, mid, Ls, ami[o]);
stmi(mid + 1, r, Rs, ami[o]);
}
if(amx[o]) {
stmx(l, mid, Ls, amx[o]);
stmx(mid + 1, r, Rs, amx[o]);
}
ami[o] = amx[o] = 0;
}
void pushup(int o) {
t[o] = t[Ls] + t[Rs];
}
void modify(int L, int R, int l, int r, int o, int v, int opt) {
if(L <= l && r <= R) {
if(!opt) stmi(l, r, o, v);
else stmx(l, r, o, v);
return;
}
pushdown(l, r, o);int mid = l + r >> 1;
if(L <= mid) modify(L, R, l, mid, Ls, v, opt);
if(R > mid) modify(L, R, mid + 1, r, Rs, v, opt);
pushup(o);
}
data query(int L, int R, int l, int r, int o) {
if(L <= l && r <= R) return t[o];
pushdown(l, r, o);int mid = l + r >> 1;
if(R <= mid) return query(L, R, l, mid, Ls);
if(L > mid) return query(L, R, mid + 1, r, Rs);
return query(L, R, l, mid, Ls) + query(L, R, mid + 1, r, Rs);
}
int main() {
n = gi();
rep(i, 1, n) a[i] = gi(), V[i] = a[i];
sort(V + 1, V + 1 + n);
vc = unique(V + 1, V + 1 + n) - V - 1;
rep(i, 1, n) a[i] = lower_bound(V + 1, V + 1 + vc, a[i]) - V;
rep(i, 1, n) {
L[i] = lst[a[i]] + 1;
lst[a[i]] = i;
}
rep(i, 1, vc) lst[i] = n + 1;
for(int i = n; i; --i) {
R[i] = lst[a[i]] - 1;
lst[a[i]] = i;
}
for(int i = 1, gg = 1; i <= n; ++i) {
for(; tp1 && L[i] >= L[st1[tp1]]; --tp1) {
modify(st1[tp1 - 1] + 1, st1[tp1], 1, n, 1, mod - L[st1[tp1]], 1);
}
modify(st1[tp1] + 1, i, 1, n, 1, L[i], 1);
st1[++tp1] = i;
for(; tp2 && R[i] <= R[st2[tp2]]; --tp2) {
modify(st2[tp2 - 1] + 1, st2[tp2], 1, n, 1, mod - R[st2[tp2]], 0);
}
modify(st2[tp2] + 1, i, 1, n, 1, R[i], 0);
st2[++tp2] = i; Max(gg, L[i]);
data res = query(gg, i, 1, n, 1);
LL tmp = ((res.smi + i * res.mx % mod - res.tm - (s1(i) - s1(gg - 1)) % mod * i % mod) % mod + mod) % mod;
add(ans, tmp);
}
printf("%lld\n", ans);
return 0;
}

[CF1083D]The Fair Nut’s getting crazy[单调栈+线段树]的更多相关文章

  1. 洛谷P4198 楼房重建 单调栈+线段树

    正解:单调栈+线段树 解题报告: 传送门! 首先考虑不修改的话就是个单调栈板子题昂,这个就是 然后这题的话,,,我怎么记得之前考试好像有次考到了类似的题目昂,,,?反正我总觉着这方法似曾相识的样子,, ...

  2. 2018宁夏邀请赛 L Continuous Intervals(单调栈+线段树)

    2018宁夏邀请赛 L Continuous Intervals(单调栈+线段树) 传送门:https://nanti.jisuanke.com/t/41296 题意: 给一个数列A 问在数列A中有多 ...

  3. The Preliminary Contest for ICPC China Nanchang National Invitational I. Max answer (单调栈+线段树)

    题目链接:https://nanti.jisuanke.com/t/38228 题目大意:一个区间的值等于该区间的和乘以区间的最小值.给出一个含有n个数的序列(序列的值有正有负),找到该序列的区间最大 ...

  4. 2019南昌网络赛-I(单调栈+线段树)

    题目链接:https://nanti.jisuanke.com/t/38228 题意:定义一段区间的值为该区间的和×该区间的最小值,求给定数组的最大的区间值. 思路:比赛时还不会线段树,和队友在这题上 ...

  5. 网络赛 I题 Max answer 单调栈+线段树

    题目链接:https://nanti.jisuanke.com/t/38228 题意:在给出的序列里面找一个区间,使区间最小值乘以区间和得到的值最大,输出这个最大值. 思路:我们枚举每一个数字,假设是 ...

  6. 南昌邀请赛I.Max answer 单调栈+线段树

    题目链接:https://nanti.jisuanke.com/t/38228 Alice has a magic array. She suggests that the value of a in ...

  7. 【CF671E】Organizing a Race 单调栈+线段树

    [CF671E]Organizing a Race 题意:n个城市排成一排,每个城市内都有一个加油站,赛车每次经过第i个城市时都会获得$g_i$升油.相邻两个城市之间由道路连接,第i个城市和第i+1个 ...

  8. 南昌网络赛 I. Max answer (单调栈 + 线段树)

    https://nanti.jisuanke.com/t/38228 题意给你一个序列,对于每个连续子区间,有一个价值,等与这个区间和×区间最小值,求所有子区间的最大价值是多少. 分析:我们先用单调栈 ...

  9. 2019ICPC南昌邀请赛网络赛 I. Max answer (单调栈+线段树/笛卡尔树)

    题目链接 题意:求一个序列的最大的(区间最小值*区间和) 线段树做法:用单调栈求出每个数两边比它大的左右边界,然后用线段树求出每段区间的和sum.最小前缀lsum.最小后缀rsum,枚举每个数a[i] ...

随机推荐

  1. ecsop文件结构

    Ecshop文件结构 :ecshop二次开发手册,ECSHOP文件结构,ECSHOP目录详解 /*ECShop 最新程序 的结构图及各文件相应功能介绍ECShop文件结构目录┣ activity.ph ...

  2. 斯诺克台球比赛规则 (Snooker)

    斯诺克台球比赛规则 斯诺克(Snooker)的意思是“阻碍.障碍”,所以斯诺克台球有时也被称为障碍台球.此项运动使用的球桌长约3569毫米.宽1778毫米,台面四角以及两长边中心位置各有一个球洞,使用 ...

  3. CentOS7 安装 JDK

    安装步骤 1. 将 jdk 安装包传到 用户 centos 的 home 目录 (/home/centos) 通过 Xftp 将安装包( jdk-8u161-linux-x64.tar.gz )传到用 ...

  4. .NET Core 环境下使用命令行移除某个 nuget 包的具体方法

    .NET Core 使用Nuget包一般是先写入csproj文件,然后下载保存在\bin\Debug\netcoreapp2.0\publish\下,所以可以采用如下方案进行删除操作(其中netcor ...

  5. 用JS制作《飞机大作战》游戏_第3讲(玩家发射子弹)-陈远波

    一.公布上一讲中玩家飞机上.下.右移动实现的代码: /*=========================键盘按下事件 keycode为得到键盘相应键对应的数字==================== ...

  6. ArcGIS API for Javascript之专题图的制作(四)热力图渲染(上)

    一 .热力图定义 热力图(heat map)也称热图,是以特殊颜色高亮区域的形式表示密度.温度.气压.频率等分布的不易理解和表达的数据. 二.HeatmapRenderer esri/renderer ...

  7. [转]MFC下关于“建立空文档失败”问题的分析

    这类问题的出现主要在bool CWinApp::ProcessShellCommand(CCommandLineInfo& rCmdInfo); 函数的关键内容: BOOL bResult = ...

  8. nodeJS-使用buffer类处理二进制数据

    使用buffer类处理二进制数据 在客户端javascript脚本代码中,对于二进制数据并没有提供一个很好的支持.然后在nodejs中需要处理像TCP流或文件流时,必须要处理二进制数据.因此在node ...

  9. JavaScript函数注意点

    1.return 请注意,函数体内部的语句在执行时,一旦执行到return时,函数就执行完毕,并将结果返回.因此,函数内部通过条件判断和循环可以实现非常复杂的逻辑. 如果没有return语句,函数执行 ...

  10. 开启路由转发 - route add -net 0.0.0.0 netmask 0.0.0.0 gateway 192.168.0.131 window tracert 追踪路由

    1.登录方式内网访问172.28.101.0/19网段的方法:在192.168.1.0/24网段的上网机器上,或在自己的操作机上加个192.168.1.0网段的ip,注意不要跟别人设置的冲突了,并添加 ...