问题B : 绝地求生 珂朵莉树

题目描述
吃鸡开局了,你降落的森林中有一条长度为S的小路(编号从1到S),且在小路上时常会起雾,你手上的激光发射器可以让雾消散。
你肯定你所在位置的视野。若位置x有浓雾,则位置x的视野为0。若从x一直到S或从x一直到1全都没有浓雾,则视野为INF。其他情况下,位置x的视野定义为max{R-L-1},其中L,R满足:,x0格子没有浓雾。
具体来说,会有以下事件发生:
1、“1 L R”小路的[L,R]部分产生了浓雾;
2、“2 L R”小路的[L,R]部分浓雾散去了;
3、“3 X”查询X点的视野。
一开始,小路上没有任何浓雾。

输入
第一行一个整数,为小路的长度S。
第二行一个整数,为事件数Q。
接下来Q行,每行一个事件,格式如题目描述。

输出
对于每一个询问事件,输出一个整数或一行字符串“INF”,代表所求视野。

样例输入
复制样例数据
5
5
1 2 4
3 1
3 4
2 3 3
3 3
样例输出
INF
0
1

提示
对于 40%的数据,SQ <= 510^7。
对于 100%的数据,2≤S≤100,000,2≤Q≤200,000,1≤L≤R≤S,1≤X≤S。

这个题目用线段树不会写, 网上的题解看的也迷迷糊糊的,忽然发现一个很很牛逼又很玄学的做法
珂朵莉树

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
using namespace std;
typedef long long ll ;
const int N = 1e5 + 10 , mod = 1e9 + 7 ;
struct node
{
    int l , r ;
    mutable ll val ;
    bool operator<(const node o) const {
    return l < o.l ;
    }
};
int n , q , ans , op , l , r , x , y ;
set<node> T ;
typedef set<node>::iterator It ;
It split(int pos)
{
    It it = T.lower_bound({pos , pos , 0}) ;
    if(it != T.end() && it->l == pos) return it ;
    -- it ;
    int L = it->l , R = it->r ;
    ll val = it->val ;
    T.erase(it) , T.insert({L , pos - 1 , val}) ;
    return T.insert({pos , R , val}).first ;
}
void Assign(int l , int r , int val)
{
    It itr = split(r + 1) , itl = split(l) ;
    T.erase(itl , itr) , T.insert({l , r , 1ll * val}) ;
}
void query(int x)
{
    It pos = split(x) ;
    if(pos->val == 1)
     {
        puts("0") ;
        return ;
     }
     int l = 1 , r = n ;
     for(It i = pos ;  ;i --)
      {
        if(i->val == 1)
         {
            l = i->r + 1 ;
            break ;
           }
           if(i == T.begin()) break ;
      }
      for(It i = pos ;i != T.end() ;i ++)
       {
        if(i->val == 1)
         {
            r = i->l - 1 ;
            break ;
            }
       }
       if(l == 1 || r == n)
        {
            puts("INF") ;
        }
        else printf("%d
" , r - l + 1) ;
}
int main()
{
    scanf("%d%d" , &n , &q) ;
    T.insert({1 , n , 0}) ;
    while(q --)
    {
        scanf("%d" , &op) ;
        if( op == 1)
         {
            scanf("%d%d" , &l , &r) ;
            Assign(l , r , 1) ;
         }
         else if(op == 2)
          {
            scanf("%d%d" , &l , &r) ;
            Assign(l , r , 0) ;
          }
          else
          {
            scanf("%d" , &l) ;
            query(l) ;
          }
    }
    return 0 ;
}
每次做题提醒自己:题目到底有没有读懂,有没有分析彻底、算法够不够贪心、暴力够不够优雅。
原文地址:https://www.cnblogs.com/spnooyseed/p/12870898.html