太原理工大大学2019校赛 L Mars Automaton(珂朵莉树模板题 ODT)

题意

为了获取实验数据,研究员想要知道在区间[l, r]上有多少种不同大小的机器人。
形式化地说,对于一个长度为n的初始全1序列,之后会有多次三种操作:

  1. 将区间[l, r]上的值全部修改为1。
  2. 将区间[l, r]上的所有值求和,覆盖位置r上的值,之后区间内所有非r位置的值都会被设置为0。
  3. 询问区间[l,r]上有多少种不同的非0数字。
思路

珂朵莉树模板题 ,以前cf遇到过好像还没存过板子。
基本模型就是 数据随机 存在区间整体推平操作(就是把一段区间的值变成一样) 可以使得期望的存在区间很少 就可以暴力的进行区间遍历。 其余时候是把 区间当作一个单位按顺序存在set里,注意区间都是断开的,也就是 线段上每个点都只存在一个区间里,但是相邻的区间就算权值相同也不一定合在一起,就是存在两个相邻区间但是值也相同的情况,所以不能简单认为一个区间内的数字个数就是 set里面这段范围内区间的个数,实际上权值个数是小于等于区间个数的。

代码
#include<bits/stdc++.h>
using namespace std;
#define maxn 1000005
#define maxm 1006
#define ll long long int
#define INF 0x3f3f3f3f
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,r,l) for(int i=r;i>=l;i--)
#define mem(a) memset(a,0,sizeof(a))
#define sqr(x) (x*x)
#define inf (ll)2e18+1
#define PI acos(-1)
#define mod 1000000007
#define auto(i,x) for(int i=head[x];i;i=ed[i].nxt)
#define IT set<node>::iterator
ll read(){
    ll x=0,f=1ll;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
     while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
     return f*x;
}
int n,m;
struct node{
    int l,r;
    mutable ll v;
    node(){};
    node(int L, int R=-1, ll V=0):l(L), r(R), v(V) {}
    bool operator<(const node& o) const
    {
        return l < o.l;
    }
};
set<node>s;
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-1, V));
    return s.insert(node(pos, R, V)).first;
}
void add(int l, int r, ll val)
{
    IT itr = split(r+1),itl = split(l);
    for (; itl != itr; ++itl)
    { itl->v=val; }
}
void assign_val(int l, int r, ll val)
{
    IT itr = split(r+1),itl = split(l);
    s.erase(itl, itr);
    s.insert(node(l, r, val));
}
ll sum(int l, int r)
{
    IT itr = split(r+1),itl = split(l);
    ll res = 0;
    for (; itl != itr; ++itl)
        res = res + (ll)(itl->r - itl->l + 1) * itl->v ;
    return res;
}
int cont(int l,int r){
    IT itr = split(r+1),itl = split(l);
    vector<ll>v;
    for (; itl != itr; ++itl)
        v.push_back(itl->v);
    sort(v.begin(),v.end());
    int len=unique(v.begin(),v.end())-v.begin();
    if(v[0]==0)len--;
    return len;
}
int main()
{
    n=read();m=read();
    s.insert(node(1,n,1));
    int op,x,y;
    inc(i,1,m){
        op=read();x=read();y=read();
        if(op==1){
            assign_val(x,y,1);
        }
        else if(op==2){
            ll res=sum(x,y);
            assign_val(x,y-1,0);
            assign_val(y,y,res);
        }
        else printf("%d\n",cont(x,y));
    }
    return 0;
}
/*
1000 11
3 1 200
2 633 635
3 1 200
1 656 789
2 688 953
3 95 661
3 398 602
1 653 769
1 364 440
2 205 422
2 186 981
*/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值