貌似珂朵莉树是目前为止(我学过的)唯一一个可以维护区间x次方和查询的高效数据结构。

但是这玩意有个很大的毛病,就是它的高效建立在数据随机的前提下。

在数据随机的时候assign操作比较多,所以它的复杂度会趋近于mlogn(m为询问次数)。假如出题人想要卡珂朵莉树的话,那肯定是会T得没边。

因此不要指望什么题目都套珂朵莉树(虽然它能水过很多数据结构题),特别是在数据非随机的情况下不要使用。

当然,如果题目让你求区间x次方和而在题目条件下你想不出巧算,那写一颗珂朵莉树还是很OK的。


不得不说珂朵莉树的博客我也看了很多篇了,大家却一笔带过(可能是我太弱了)细节只讲大致框架,而某大佬在B站上的视频讲解被某不知名的毒瘤lxl喷了所以没敢去看,只好一个人颓代码。

我讲的也不一定多标准,有什么错误麻烦各位指正。

另:不太熟悉set的可以参考这篇博客


珂朵莉树的核心操作在于推平一个区间。

(貌似每篇博客都说这句话)

当然事实上珂朵莉树是将所有要操作的区间整合到一起去做的,实现也可以不依赖set,比如自己写一颗fhq Treap之类的。

先讲一下大体思路:

可以发现,这里面有一个操作是推平一整段区间。

因此我们让每一个节点维护一个区间,然后对于2号操作清空区间[l,r]里的所有区间,用一个大区间[l,r]取代他们。

对于1,3,4号操作,我们暴力地找到每一个[l,r]里面的区间,然后对它们各个进行操作。

时间复杂度的证明可以参考发明者的原话:传送门(注意是第五条)


珂朵莉树的节点是这样定义的:

 struct node{
int l,r;mutable ll v;
node(int L,int R=-,ll V=):l(L),r(R),v(V){}
bool operator < (const node &o)const{
return l<o.l;
}
};

这个节点维护的是区间[l,r],里面的每个数都初始化为v。


有了基本的节点之后,通过set建立一棵树。

(set是C++自带的平衡树,但是慢到一种境界。只有在刷时限给力的题目时推荐)

set<node> s;


然后是很核心的split操作,这个操作如同它的名字,将一个区间拆分开来。

 #define IT set<node>::iterator
IT split(int pos){
IT it=s.lower_bound(node(pos));
if(it!=s.end()&&it->l==pos)return it;
it--;
int L=it->l,R=it->r;ll V=it->v;s.erase(it),s.insert(node(L,pos-,V));
return s.insert(node(pos,R,V)).first;
}

IT代表的玩意建议用宏,手打可以让你怀疑人生。

第一行使用了lower_bound,这个函数的作用是求前驱。

然后我们先看是否需要split这个区间,如果不需要就直接返回it。

假如现在程序还在运行,那说明我们需要split。

因此pos肯定在上一个区间里(显然),那我们把前一个彻底抹掉,然后再插入两段区间。

现在看来我们什么事情都没有做,删掉了区间又把它放回来了。

注意,其实我们并不是什么事情都没有做,因为我们在这个过程中已经拿到了需要的东西:后半段区间的迭代器(什么用后面说)

最后的返回语句可能比较玄学,事实上,set的insert操作返回一个<iterator,bool>的pair,我们只拿走第一个。

split操作就这样结束了,它的复杂度应该是log级的(set通过红黑树实现,而那玩意(我没写过)的操作据说是近似logn的)。


同样核心的assign操作,是将一个区间的每一个值都设为一个值。

 void assign(int l,int r,int val=){
IT itl=split(l),itr=split(r+);
s.erase(itl,itr),s.insert(node(l,r,val));
}

val默认为0(因为很多时候我们直接推平)。

首先我们拿到itl和itr,这两个东西分别是split(l)与split(r+1)的返回值,看起来可能不太好理解,但是画个图似乎挺明了的。

然后我们把中间的都删除(这是erase的另一种用法,删除区间内的所有元素),用一个大区间代替所有小区间。

没了,时间复杂度很能接受。


add操作,给区间每个数加上val。

 void add(int l,int r,ll val=){
IT itl=split(l),itr=split(r+);
for(;itl!=itr;++itl)itl->v+=val;
}

像我们之前说的那样,对于[l,r]内的所有小区间,暴力遍历一遍,给他们每一个都加上val。

可能有人会问:不会有加重复或者漏加的情况吗?

事实上不会。

漏加这个很明显是没有的,而重复加之所以没有是因为

1. 最开始没有重复。

2. 每一次推平不会产生重复。


接下来是求区间k小值。

 ll rank(int l,int r,int k){
vector<pair<ll,int> >vp;vp.clear();
IT itl=split(l),itr=split(r+);
for(;itl!=itr;++itl)vp.push_back(pair<ll,int>(itl->v,itl->r-itl->l+));
sort(vp.begin(),vp.end());
for(vector<pair<ll,int> >::iterator it=vp.begin();it!=vp.end();++it){
k-=it->second;
if(k<=)return it->first;
}
return -1ll;
}

我们采取类似的思路:把[l,r]里面的所有元素取出来,扔到一个vector里面去。

然后给这个vector排个序。

便利一遍就可以找到最小值了。

最后的return -1ll;是特判找不到的情况,当然本题保证找得到。


最后一个操作是区间x次方和,这个也十分暴力:

 ll sum(int l,int r,int ex,int mod){
IT itl=split(l),itr=split(r+);ll res=;
for(;itl!=itr;++itl)res=(res+(ll)(itl->r-itl->l+)*power(itl->v,(ll)ex,(ll)mod))%mod;
return res;
}

对于[l,r]每一个元素都暴力x次方,这个过程通过快速幂实现。


然后珂朵莉树的操作基本就完了。

有人问我为什么代码都这么一样。

我也很无奈啊,只能说我学习的那篇博客和大家重复了qwq。

题解 CF896C 【Willem, Chtholly and Seniorious】的更多相关文章

  1. 【ODT】cf896C - Willem, Chtholly and Seniorious

    仿佛没用过std::set Seniorious has n pieces of talisman. Willem puts them in a line, the i-th of which is ...

  2. [CF896C]Willem, Chtholly and Seniorious(珂朵莉树)

    https://www.cnblogs.com/WAMonster/p/10181214.html 主要用于支持含有较难维护的区间操作与查询的问题,要求其中区间赋值操作(assign())是纯随机的. ...

  3. 【题解】Willem, Chtholly and Seniorious Codeforces 896C ODT

    Prelude ODT这个东西真是太好用了,以后写暴力骗分可以用,写在这里mark一下. 题目链接:ヽ(✿゚▽゚)ノ Solution 先把原题解贴在这里:(ノ*・ω・)ノ 简单地说,因为数据是全部随 ...

  4. [CF896C]Willem, Chtholly and Seniorious

    题目大意:有$n$个数,有$m$次$4$种操作: l r x :将$[l,r]$区间所有数加上$x$ l r x :将$[l,r]$区间所有数变成$x$ l r k :输出$[l,r]$区间第$k$大 ...

  5. cf896C. Willem, Chtholly and Seniorious(ODT)

    题意 题目链接 Sol ODT板子题.就是用set维护连续段的大暴力.. 然鹅我抄的板子本题RE提交AC??.. 具体来说,用50 50 658073485 946088556这个数据测试下面的代码, ...

  6. CF896C Willem, Chtholly and Seniorious(珂朵莉树)

    中文题面 珂朵莉树的板子……这篇文章很不错 据说还有奈芙莲树和瑟尼欧里斯树…… 等联赛考完去学一下(逃 //minamoto #include<bits/stdc++.h> #define ...

  7. Willem, Chtholly and Seniorious

    Willem, Chtholly and Seniorious https://codeforces.com/contest/897/problem/E time limit per test 2 s ...

  8. CF&&CC百套计划1 Codeforces Round #449 C. Willem, Chtholly and Seniorious (Old Driver Tree)

    http://codeforces.com/problemset/problem/896/C 题意: 对于一个随机序列,执行以下操作: 区间赋值 区间加 区间求第k小 区间求k次幂的和 对于随机序列, ...

  9. 【CF896C】Willem, Chtholly and Seniorious

    ODT模板题,ODT适合随机数据下具有维护区间推平操作的序列维护题目,时间复杂度较为玄学.. 代码如下 #include <bits/stdc++.h> #define pb push_b ...

随机推荐

  1. 准备把平台挪到linux

    在上午准备周末胡老师的课程考核的Ppt时,逐渐我觉得不得不把平台挪到linux了.很多并行的应用不只是在linux上效率更高,而且很多包都在linux上.另外如果不及早挪到Linux上,后面遇到的问题 ...

  2. vmware workstation pro 14 虚拟机无法开启、黑屏的解决方案汇总

    方案1:卸载鲁大师,重启. 方案2:管理员命令行,输入netsh winsock reset,重启. 方案3:360安全管家修复LSP,重启. 方案4:卸载14.0,安装12.0,手动导入虚拟机.

  3. JavaScript学习——完善注册页面表单校验

    1.之前我们已经使用弹出框的方式实现了表单校验的功能,但是此种方式用户体验效果很差 我们希望做成把提示信息和校验结果放在输入栏的后面. 2.步骤分析 (此案例基于HTML&CSS——网站注册页 ...

  4. Linux与Windows信息交互快捷方法

    要把windows上的D盘挂载的Linux上,首先要知道windows的用户名和密码 假设用户名是administrator,密码是123456 首先,在linux上创建一个挂载的目标目录 mkdir ...

  5. poj1170 - 转换成背包

    题目链接 有5种物品,给出每个物品的单价. 给出几个这些物品的组合和这个组合的价格.买组合要比一件件的买便宜. 问给定的购买计划最少花多少钱. ---------------------------- ...

  6. javascript工具--控制台详解

    一.显示信息的命令 console.log();  //控制台输入 网页中不会输出 console.info();  //一般信息 console.debug();  //除错信息 console.w ...

  7. shell-3.bash的基本功能:输入输出重定向

    1. 2. 3. 4.

  8. 1113: [视频]树形动态规划(TreeDP)8:树(tree)(树形dp状态设计总结)

    根据最近做的几道树形dp题总结一下规律.(从这篇往前到洛谷 P1352 ) 这几道题都是在一颗树上,然后要让整棵树的节点或边 满足一种状态.然后点可以影响到相邻点的这种状态 然后求最小次数 那么要从两 ...

  9. docker 下修改 mysql sql_mode和配置文件

    原文:docker 下修改 mysql sql_mode和配置文件 打开PowerShell 首先创建mysql容器,这里我们指定使用mysql5.7的版本 docker run -d -p 3306 ...

  10. hdu5137 How Many Maos Does the Guanxi Worth(单源最短路径)

    题目链接:pid=5137">点击打开链接 题目描写叙述:如今有一张关系网.网中有n个结点标号为1-n.有m个关系,每一个关系之间有一个权值.问从2-n-1中随意去掉一个结点之后,从1 ...