珂朵莉
首先要明白的是:珂朵莉树(ODT)是一种用来骗分的暴力数据结构。
珂朵莉树的思想是利用集合set,把相同且连续的元素合并为一个个区间,从而进行区间修改;因此,珂朵莉树是区间的集合,这点可以通过定义结构体来实现。
珂朵莉树由两个核心操作构成:
1、split(分裂)
通过split,我们可以将一个区间分为两段,例如对于区间中的位置,就是把区间分为两段。
split返回值是一个iterator,它对应的区间是。
2、assign_val(区间推平)
通过(注意右端点分裂时要加一),可以提取任意区间,而区间推平就是把整段区间修改为某一个值,因此通过,再(其中为区间对应的结构体,为要修改的值),就可以实现区间推平操作。
关于定义珂朵莉树的方法和这些操作的具体实现方法,大家在网上应该可以搜到yzhang的博客和B站UESTC算法讲堂的视频讲解,因此我就不多赘述了。
但是,以上讲解的例题多数是一些专门为珂朵莉树设计的题,有没有在实际比赛中的应(pian)用(fen)案例呢?
确实有,这里我就找到了一题:[SCOI2010]序列操作
大家可以看到题解中的线段树标程从4K-6K不等,然后再看下珂朵莉树解法:
时间效率是不是看起来一点都不像暴力?
言归正传,为什么这题可以用珂朵莉树?可以看到题面中有如下操作:
0 a b 把[a, b]区间内的所有数全变成0
1 a b 把[a, b]区间内的所有数全变成1
这种需要将区间整段赋值的题,在数据随机的情况下,珂朵莉树的效率非常高。
于是我们尝试用珂朵莉树进行维护:对于操作0、1可以用珂朵莉树的区间推平实现,而操作2则利用split提取区间后依次取反,操作3、4也同理,利用split提取区间进行相应操作。
那么,上代码:
#include<cstdio>
#include<set>
using namespace std;
struct node
{
int l,r;
mutable bool v;
node(int L,int R=-1,bool V=0)
{
l=L;
r=R;
v=V;
};
bool operator<(const node&next) const
{
return l<next.l;
}
};
set<node> Chtholly_tree;
int n,m;
set<node>::iterator split(int pos)
{
set<node>::iterator it=Chtholly_tree.lower_bound(node(pos));
if (it!=Chtholly_tree.end()&&it->l==pos) return it;
it--;
int left=it->l;
int right=it->r;
int temp=it->v;
Chtholly_tree.erase(it);
Chtholly_tree.insert(node(left,pos-1,temp));
return Chtholly_tree.insert(node(pos,right,temp)).first;
}
void assign_val(int l,int r,int temp)
{
set<node>::iterator itr=split(r+1);
set<node>::iterator itl=split(l);
Chtholly_tree.erase(itl,itr);
Chtholly_tree.insert(node(l,r,temp));
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
{
int t;
scanf("%d",&t);
Chtholly_tree.insert(node(i,i,t));
}
Chtholly_tree.insert(node(n+1,n+1,0));
for (int i=1;i<=m;i++)
{
int opt,a,b;
scanf("%d%d%d",&opt,&a,&b);
a++;
b++;
if (opt==0)
assign_val(a,b,0);
else if (opt==1)
assign_val(a,b,1);
else if (opt==2)
{
set<node>::iterator itr=split(b+1);
set<node>::iterator itl=split(a);
for (;itl!=itr;itl++)
itl->v=!itl->v;
}
else if (opt==3)
{
int ans=0;
set<node>::iterator itr=split(b+1);
set<node>::iterator itl=split(a);
for (;itl!=itr;itl++)
if (itl->v)
ans+=itl->r-itl->l+1;
printf("%d\n",ans);
}
else if (opt==4)
{
int ans=0;
int now=0;
set<node>::iterator itr=split(b+1);
set<node>::iterator itl=split(a);
for (;itl!=itr;itl++)
if (itl->v)
now+=itl->r-itl->l+1;
else if (!itl->v)
{
ans=max(ans,now);
now=0;
}
ans=max(ans,now);
printf("%d\n",ans);
}
/*printf("\n");
set<node>::iterator it=Chtholly_tree.begin();
for (;it!=Chtholly_tree.end();it++)
printf("%d %d %d\n",it->l,it->r,it->v);
printf("\n");*/
}
return 0;
}
文章最后发布于: 2019-06-27 17:21:31
相关阅读
哈喽,你我相约七点半,你来了么^_^产品经理日报继续为您带来今日最新的资讯:美团正式入局共享充电宝,行业竞争加剧;Snapchat新功能,用人
史蒂芬说:在首届“微店大会”上,口袋购物微店创始人王珂首次公布了公司的C轮融资总额达到3.5亿美金,在兴奋之余,竟直接吐槽了其A轮投