线段树上\(DP\)

首先发现,每个数肯定是向自己的前驱或后继连边的。

则我们开一棵权值线段树,其中每一个节点记录一个\(f_{0/1,0/1}\),表示在这个区间左、右端点是否连过边的情况下,使这个区间符合条件的最小代价。

合并时考虑如果左儿子的右端点或右儿子的左端点中有一个没有连过边,就必须连边,否则就不连边。

然后我的写法比较蠢,不知道为什么当左右儿子中某个节点只有一个数时需要特判处理。

最后答案就是根节点的\(f_{1,1}\)。

具体详见代码。

代码

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 200000
#define V 1000000000
#define LV 30
#define LL long long
#define INF 1e18
#define min(x,y) ((x)<(y)?(x):(y))
#define Gmin(x,y) (x>(y)&&(x=(y)))
using namespace std;
int n,Qt,a[2*N+5];
class FastIO
{
private:
#define FS 100000
#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
#define pc(c) (C==E&&(clear(),0),*C++=c)
#define tn (x<<3)+(x<<1)
#define D isdigit(c=tc())
int T;char c,*A,*B,*C,*E,FI[FS],FO[FS],S[FS];
public:
I FastIO() {A=B=FI,C=FO,E=FO+FS;}
Tp I void read(Ty& x) {x=0;W(!D);W(x=tn+(c&15),D);}
Tp I void write(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);}
Tp I void writeln(Con Ty& x) {write(x),pc('\n');}
I void clear() {fwrite(FO,1,C-FO,stdout),C=FO;}
#undef D
}F;
class SegmentTreeSolver
{
private:
template<int SZ> class SegmentTree//线段树
{
private:
#define F5(x,l,r)\
O[x].f[l][r]=O[O[x].S[0]].f[l][1]+O[O[x].S[1]].f[1][r],\
Gmin(O[x].f[l][r],O[O[x].S[0]].f[l][0]+O[O[x].S[1]].f[0][r]+O[O[x].S[1]].L-O[O[x].S[0]].R),\
Gmin(O[x].f[l][r],O[O[x].S[0]].f[l][0]+O[O[x].S[1]].f[1][r]+O[O[x].S[1]].L-O[O[x].S[0]].R),\
Gmin(O[x].f[l][r],O[O[x].S[0]].f[l][1]+O[O[x].S[1]].f[0][r]+O[O[x].S[1]].L-O[O[x].S[0]].R)//普通情况下转移
int n,rt,Nt;struct node//维护节点信息
{
int Ex,L,R,S[2];LL f[2][2];
I node(CI x=0):Ex(0),L(x),R(x),S({0,0}),f({{0,INF},{INF,INF}}){}
I void operator = (Con node& o)
{
Ex=o.Ex,L=o.L,R=o.R,f[0][0]=o.f[0][0],f[0][1]=o.f[0][1],
f[1][0]=o.f[1][0],f[1][1]=o.f[1][1];
}
}O[SZ+5];
I void PU(CI x)//上传信息
{
if(!O[O[x].S[0]].Ex) return (void)(O[x]=O[O[x].S[1]]);//如果没有左儿子
if(!O[O[x].S[1]].Ex) return (void)(O[x]=O[O[x].S[0]]);//如果没有右儿子
O[x].Ex=1,O[x].L=O[O[x].S[0]].L,O[x].R=O[O[x].S[1]].R;//上传基础信息
if(O[O[x].S[0]].L==O[O[x].S[0]].R&&O[O[x].S[1]].L==O[O[x].S[1]].R)//合并两个单点
{
O[x].f[0][0]=0,O[x].f[1][1]=O[O[x].S[1]].L-O[O[x].S[0]].R,
O[x].f[0][1]=O[x].f[1][0]=INF;return;
}
if(O[O[x].S[0]].L==O[O[x].S[0]].R)//合并单点和区间
{
O[x].f[1][0]=min(O[O[x].S[1]].f[0][0],O[O[x].S[1]].f[1][0])+O[O[x].S[1]].L-O[O[x].S[0]].R,
O[x].f[1][1]=min(O[O[x].S[1]].f[0][1],O[O[x].S[1]].f[1][1])+O[O[x].S[1]].L-O[O[x].S[0]].R,
O[x].f[0][0]=O[O[x].S[1]].f[1][0],O[x].f[0][1]=O[O[x].S[1]].f[1][1];return;
}
if(O[O[x].S[1]].L==O[O[x].S[1]].R)//合并区间和单点
{
O[x].f[0][1]=min(O[O[x].S[0]].f[0][0],O[O[x].S[0]].f[0][1])+O[O[x].S[1]].L-O[O[x].S[0]].R,
O[x].f[1][1]=min(O[O[x].S[0]].f[1][0],O[O[x].S[0]].f[1][1])+O[O[x].S[1]].L-O[O[x].S[0]].R,
O[x].f[0][0]=O[O[x].S[0]].f[0][1],O[x].f[1][0]=O[O[x].S[0]].f[1][1];return;
}
F5(x,0,0),F5(x,0,1),F5(x,1,0),F5(x,1,1);
}
I void Upt(CI x,CI v,CI l,CI r,int& rt)//单点修改
{
if(!rt&&(rt=++Nt),l==r) return (void)(!O[rt].Ex&&(O[rt]=node(l),0),O[rt].Ex+=v);
RI mid=l+r>>1;x<=mid?Upt(x,v,l,mid,O[rt].S[0]):Upt(x,v,mid+1,r,O[rt].S[1]),PU(rt);
}
public:
I void Init(CI _n) {n=_n;}I void Upt(CI x,CI v) {Upt(x,v,1,n,rt);}
I LL Qry() {return O[rt].f[1][1];}//询问
};SegmentTree<N*LV> S;
public:
I void Solve()
{
RI i,op,x;for(S.Init(V),i=1;i<=n;++i) S.Upt(a[i],1);//初始化
W(Qt--) F.read(op),F.read(x),S.Upt(x,op==1?1:-1),F.writeln(S.Qry());//处理操作
}
}S;
int main()
{
freopen("set.in","r",stdin),freopen("set.out","w",stdout);
RI i;for(F.read(n),F.read(Qt),i=1;i<=n;++i) F.read(a[i]);
return sort(a+1,a+n+1),S.Solve(),F.clear(),0;
}

【2019.8.6 慈溪模拟赛 T3】集合(set)(线段树上DP)的更多相关文章

  1. 【2019.8.11上午 慈溪模拟赛 T3】欢迎回来(back)(设阈值+莫队)

    设阈值 考虑对于询问的\(d\)设阈值进行分别处理. 对于\(d\le\sqrt{max\ d}\)的询问,我们可以\(O(n\sqrt{max\ d})\)预处理答案,\(O(1)\)输出. 对于\ ...

  2. 【2019.8.15 慈溪模拟赛 T1】插头(plugin)(二分+贪心)

    二分 首先,可以发现,最后的答案显然满足可二分性,因此我们可以二分答案. 然后,我们只要贪心,就可以验证了. 贪心 不难发现,肯定会优先选择能提供更多插座的排插,且在确定充电器个数的情况下,肯定选择能 ...

  3. 【2019.10.7 CCF-CSP-2019模拟赛 T3】未知的数组(unknown)(并查集+动态规划)

    预处理 考虑模数\(10\)是合数不好做,所以我们可以用一个常用套路: \(\prod_{i=l}^ra_i\equiv x(mod\ 10)\)的方案数等于\(\prod_{i=l}^ra_i\eq ...

  4. 【2019.8.20 NOIP模拟赛 T3】小X的图(history)(可持久化并查集)

    可持久化并查集 显然是可持久化并查集裸题吧... 就是题面长得有点恶心,被闪指导狂喷. 对于\(K\)操作,直接\(O(1)\)赋值修改. 对于\(R\)操作,并查集上直接连边. 对于\(T\)操作, ...

  5. 【2019.8.15 慈溪模拟赛 T2】组合数(binom)(卢卡斯定理+高维前缀和)

    卢卡斯定理 题目中说到\(p\)是质数. 而此时要求组合数向质数取模的结果,就可以用卢卡斯定理: \[C_x^y=C_{x\ div\ p}^{y\ div\ p}\cdot C_{x\ mod\ p ...

  6. 【2019.8.6 慈溪模拟赛 T2】树上路径(tree)(Trie)

    从暴力考虑转化题意 考虑最暴力的做法,我们枚举路径的两端,然后采用类似求树上路径长度的做法,计算两点到根的贡献,然后除去\(LCA\)到根的贡献两次. 即,设\(v_i\)为\(i\)到根路径上的边权 ...

  7. 【2019.8.7 慈溪模拟赛 T2】环上随机点(ran)(自然算法)

    简单声明 我是蒟蒻不会推式子... 所以我用的是乱搞做法... 大自然的选择 这里我用的乱搞做法被闪指导赐名为"自然算法",对于这种输入信息很少的概率题一般都很适用. 比如此题,对 ...

  8. 【2019.8.8 慈溪模拟赛 T1】开箱(chest)(暴力DP水过)

    转化题意 这题目乍一看十分玄学,完全不可做. 但实际上,假设我们在原序列从小到大排序之后,选择开的宝箱编号是\(p_{1\sim Z}\),则最终答案就是: \[\sum_{i=1}^Za_{p_i} ...

  9. 【2019.8.8 慈溪模拟赛 T2】query(query)(分治+分类讨论)

    分治 首先,我们考虑分治处理此问题. 每次处理区间\([l,r]\)时,我们先处理完\([l,mid]\)和\([mid+1,r]\)两个区间的答案,然后我们再考虑计算左区间与右区间之间的答案. 处理 ...

随机推荐

  1. 推荐一款可以直接下载浏览器sources资源的Chrome插件

    github地址:https://github.com/up209d/ResourcesSaverExt 经常在仿站的时候回遇到下载别人的图片.css.js等资源,发现要一个个的手动下载.直接使用仿站 ...

  2. php date获取当前时间

    结果: 结论: 本以为第一种方式最快,第三种方式竟超乎想象的快且稳定

  3. Loj #6503. 「雅礼集训 2018 Day4」Magic

    Loj #6503. 「雅礼集训 2018 Day4」Magic 题目描述 前进!前进!不择手段地前进!--托马斯 · 维德 魔法纪元元年. 1453 年 5 月 3 日 16 时,高维碎片接触地球. ...

  4. idea设置类注释和方法注释

    类注释 1.file-->setting-->editor-->file and code templates-->includes--> file header 2.在 ...

  5. 【趣学程序】Linux上安装Tengine(Nginx)

    linux 安装tengine tengine是什么 tengine是由淘宝网发起的Web服务器项目.它在Nginx的基础上,针对大访问量网站的需求,添加了很多高级功能和特性.Tengine的性能和稳 ...

  6. 关于python的十一道练习

    关于python的十一道练习 1.编写程序,输入一个自然数字符串,然后输出各位数字之和.例如,输入字符串1234,输出10. def sums1(): #第一题 strs=input('请输入一个自然 ...

  7. java高并发系列 - 第11天:线程中断的几种方式

    java高并发系列第11篇文章. 本文主要探讨一下中断线程的几种方式. 通过一个变量控制线程中断 代码: package com.itsoku.chat05; import java.util.con ...

  8. C#上手练习2(FOR语句)

    循环语句和条件语句一样都是每个程序中必不可少的,循环语句是用来完成一些重复的工作的,以减少编写代码的工作量. C# for 循环是最常用的循环语句,语法形式非常简单,多用于固定次数的循环. 具体的语法 ...

  9. Z从壹开始前后端分离【 .NET Core2.0/3.0 +Vue2.0 】框架之十 || AOP面向切面编程浅解析:简单日志记录 + 服务切面缓存

    本文梯子 本文3.0版本文章 代码已上传Github+Gitee,文末有地址 大神反馈: 零.今天完成的深红色部分 一.AOP 之 实现日志记录(服务层) 1.定义服务接口与实现类 2.在API层中添 ...

  10. JS是解释型还是编译型语言?

    解释型和编译型语言 解释型语言 解释型语言是对代码进行一句一句的直接运行,在程序运行期间,使用解释器动态将代码解释为机器码,再运行. 编译型语言 编译型语言是需要使用编译器先对代码进行编译为机器码,再 ...