题解 CF915E 【Physical Education Lessons】
CF915E Physical Education Lessons
传送门
一道简单的珂朵莉树模板题。
思路
珂朵莉树($ODT$)是一种用 $std::set$ 维护的暴力数据结构,每个节点保存三个值:$l$、$r$、$v$,表示 $l$ 、$r$ 区间的值都为 $v$ ,有区间推平操作和数据随机时可以使用这种数据结构。
除区间推平,它还可以支持许多其它的操作,如区间加、区间 $k$ 大值、区间 $k$ 次求和等。
回到这道题,它只需要区间推平与区间求和,可以使用珂朵莉树。
如果想更好地理解珂朵莉树,建议去做一下这道题,也可以看看其它 $dalao$ 的题解。
代码实现
如果直接使用区间求和求每次修改后的值是不行的,#$30$ 会 $\textcolor{#052242}{TLE}$,但是我们不求整段,直接求修改的一段增减了多少,输出即可,加个快读快输就跑得飞快。
#include<bits/stdc++.h>
using namespace std;
#define pnt pair<int,int>
#define sit set<node>::iterator
struct node{
int l,r;
mutable int v;
node(int L,int R=-1,int V=0):l(L),r(R),v(V){}
friend bool operator<(const node& a,const node &b){
return a.l<b.l;
}
};
set<node>a;
int n,m,l,r,op,ans;
inline int read(){
char ch=getchar();
int x=0;
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+(ch^48),ch=getchar();
return x;
}
inline void write(int x){
if(x<0)putchar('-'),x=-x;
if(x>9)write(x/10);
putchar(x%10^48);
}
inline sit split(int p){
sit it=a.lower_bound(node(p));
if(it!=a.end()&&it->l==p){
return it;
}
it--;
int l=it->l,r=it->r,v=it->v;
a.erase(it);
a.insert(node(l,p-1,v));
return a.insert(node(p,r,v)).first;
}
inline void assign(int l,int r,int val){
sit itr=split(r+1),itl=split(l);
for(sit it=itl;it!=itr;it++){
ans-=(it->r-it->l+1)*it->v;
}
ans+=(r-l+1)*val;
a.erase(itl,itr);
a.insert(node(l,r,val));
}
signed main(){
n=read(),m=read();
a.insert(node(1,n,1));
ans=n;
for(int i=1;i<=m;i++){
l=read(),r=read();
assign(l,r,read()-1);
write(ans);
puts("");
}
return 0;
}
/*
Time:5.78s
Memory:23.01MB
*/
再见qwq~

浙公网安备 33010602011771号