【2019.8.6 慈溪模拟赛 T3】集合(set)(线段树上DP)
线段树上\(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)的更多相关文章
- 【2019.8.11上午 慈溪模拟赛 T3】欢迎回来(back)(设阈值+莫队)
设阈值 考虑对于询问的\(d\)设阈值进行分别处理. 对于\(d\le\sqrt{max\ d}\)的询问,我们可以\(O(n\sqrt{max\ d})\)预处理答案,\(O(1)\)输出. 对于\ ...
- 【2019.8.15 慈溪模拟赛 T1】插头(plugin)(二分+贪心)
二分 首先,可以发现,最后的答案显然满足可二分性,因此我们可以二分答案. 然后,我们只要贪心,就可以验证了. 贪心 不难发现,肯定会优先选择能提供更多插座的排插,且在确定充电器个数的情况下,肯定选择能 ...
- 【2019.10.7 CCF-CSP-2019模拟赛 T3】未知的数组(unknown)(并查集+动态规划)
预处理 考虑模数\(10\)是合数不好做,所以我们可以用一个常用套路: \(\prod_{i=l}^ra_i\equiv x(mod\ 10)\)的方案数等于\(\prod_{i=l}^ra_i\eq ...
- 【2019.8.20 NOIP模拟赛 T3】小X的图(history)(可持久化并查集)
可持久化并查集 显然是可持久化并查集裸题吧... 就是题面长得有点恶心,被闪指导狂喷. 对于\(K\)操作,直接\(O(1)\)赋值修改. 对于\(R\)操作,并查集上直接连边. 对于\(T\)操作, ...
- 【2019.8.15 慈溪模拟赛 T2】组合数(binom)(卢卡斯定理+高维前缀和)
卢卡斯定理 题目中说到\(p\)是质数. 而此时要求组合数向质数取模的结果,就可以用卢卡斯定理: \[C_x^y=C_{x\ div\ p}^{y\ div\ p}\cdot C_{x\ mod\ p ...
- 【2019.8.6 慈溪模拟赛 T2】树上路径(tree)(Trie)
从暴力考虑转化题意 考虑最暴力的做法,我们枚举路径的两端,然后采用类似求树上路径长度的做法,计算两点到根的贡献,然后除去\(LCA\)到根的贡献两次. 即,设\(v_i\)为\(i\)到根路径上的边权 ...
- 【2019.8.7 慈溪模拟赛 T2】环上随机点(ran)(自然算法)
简单声明 我是蒟蒻不会推式子... 所以我用的是乱搞做法... 大自然的选择 这里我用的乱搞做法被闪指导赐名为"自然算法",对于这种输入信息很少的概率题一般都很适用. 比如此题,对 ...
- 【2019.8.8 慈溪模拟赛 T1】开箱(chest)(暴力DP水过)
转化题意 这题目乍一看十分玄学,完全不可做. 但实际上,假设我们在原序列从小到大排序之后,选择开的宝箱编号是\(p_{1\sim Z}\),则最终答案就是: \[\sum_{i=1}^Za_{p_i} ...
- 【2019.8.8 慈溪模拟赛 T2】query(query)(分治+分类讨论)
分治 首先,我们考虑分治处理此问题. 每次处理区间\([l,r]\)时,我们先处理完\([l,mid]\)和\([mid+1,r]\)两个区间的答案,然后我们再考虑计算左区间与右区间之间的答案. 处理 ...
随机推荐
- <Graph> Topological + Undirected Graph 310 Union Find 261 + 323 + (hard)305
310. Minimum Height Trees queue: degree为1的顶点 degree[ i ] : 和 i 顶点关联的边数. 先添加整个图,然后BFS删除每一层degree为1的节 ...
- fastdfs使用总结
参考:https://www.cnblogs.com/chiangchou/p/fastdfs.html 说明:这篇博客是为了记录我在安装和使用FastDFS分布式文件系统时遇到的问题和解决方法, ...
- lua require路径设置实例
1.首先要强调的是,lua require的路径用的是斜杠"/",而不是从Windows文件属性那里复制来的反斜杠"\". 2.通过 print(pagckag ...
- ASP.NET Core 集成测试中模拟登录用户的一种姿势
不管哪种用户验证方式,最终都是在验证成功后设置 HttpContext.User ,后续处理环节通过 HttpContext.User 获取用户信息.如果能直接修改 HttpContext.User ...
- 【STM32H7教程】第17章 STM32H7之GPIO的HAL库API
完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第17章 STM32H7之GPIO的HAL库API ...
- SpringBoot系列之外部配置用法简介
SpringBoot系列之外部配置用法简介 引用Springboot官方文档的说法,官方文档总共列举了如下用法: 1.Devtools global settings properties on yo ...
- git分支合并解决冲突
git分支合并,解决冲突 1.手动解决冲突 手动解决冲突,需要使用编辑器,把所有文件中出现的冲突地方修改,然后再添加到暂存区再提交 >>>>>>brancha so ...
- PriorityBlockingQueue
public class PriorityBlockingQueueTest { /** * 有优先级顺序的阻塞队列,底层实现是数组,无边界.默认是11. * 构造方法可以传入一个比较器,不传的话,默 ...
- SpringBoot中数据加密存储和获取后解密展示AttributeConverter的实现
1. 需求: 数据库存入数据的时候要加密处理,不同的字段加密方式不同. 界面上展示的时候要解密处理,解密方式相同. 2. 实现方案一: 定义公共的加密解密方法,然后在对应的字段上重写他的getset方 ...
- 【linux】linux命令--uptime查看机器存活多久和平均负载 解读平均负载含义
一.uptime命令,查看机器存活时间和平均负载 键入命令: uptime 该结果和 top命令查看结果最上面一行的 是一样的显示. 返回数据介绍: #当前服务器时间: 19:56:44 #当前服务器 ...