codeforces 915 E 珂朵莉树

题目链接

题意:有n个元素,这n个元素最初的状态都为1,对n个元素做q次操作,每次操作把给定区间置0或置1,每次操作之后都要输出这n个元素中1的个数。

乍一看以为是线段树裸题,但是看到n的数据范围我放弃了......

网上看了博客,有三种方法来做这个题:1、珂朵莉树(ODT);2、set;3、线段树动态开点。

我看了用珂朵莉树的做法,听说珂朵莉树解决区间推平问题比较好用,然后就大概学了一下。

其实什么也没学懂,珂朵莉树的关键好像是split操作,然后其他的就比较暴力了。并且珂朵莉树的复杂度比较玄学,有些题目如果数据水的话能过,如果出题人专门弄数据卡你就玩完了,所以珂朵莉树不能当作正解......

推荐一个讲珂朵莉树的视频,里面也有这道题的大致讲解,好像是成电的大佬讲的:https://www.bilibili.com/video/av21651173from=search&seid=13578438704386102893

代码参考了下面这篇博客:https://www.cnblogs.com/bztMinamoto/p/9810833.html

#include<bits/stdc++.h>
#define IT set<node>::iterator
using namespace std;
struct node
{
    int l,r;
    mutable int v;
    node(int L,int R=-1,int V=0):l(L),r(R),v(V) {}
    inline bool operator <(const node &b)const
    {
        return l<b.l;
    }
};
set<node> s;
int sum;

//把pos所在的区间[l,r]分离成[l,pos-1]和[pos+1,r]
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,v=it->v;
    s.erase(it);
    s.insert(node(l,pos-1,v?pos-l:0));
    return s.insert(node(pos,r,v?r-pos+1:0)).first;
}

//区间推平,把区间[l,r]的值置成v
void assign(int l,int r,int v)
{
    IT itr=split(r+1),itl=split(l);
    for(IT it=itl; it!=itr; ++it) sum-=it->v;
    s.erase(itl,itr),s.insert(node(l,r,v*(r-l+1)));
    sum+=v*(r-l+1);
}
int main()
{
    int n,q;
    scanf("%d%d",&n,&q);
    s.insert(node(1,n,1));
    sum=n;
    int l,r,p;
    while(q--)
    {
        scanf("%d%d%d",&l,&r,&p);
        assign(l,r,p-1);
        printf("%d\n",sum);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/flyzer/article/details/89742630
今日推荐