题解 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~

posted @ 2020-10-23 18:46  ffffyc  阅读(16)  评论(0)    收藏  举报  来源