UPC-探险(线段树+二分)

简介: UPC-探险(线段树+二分)

在乏善可陈的世界里,你熠熠生辉。

探险

时间限制: 1 Sec 内存限制: 128 MB

[提交] [状态]

题目描述

小林想去森林探险。森林中有一条长度为S的小路:

若位置x有浓雾,则位置x的视野为0;

若从x一直到S或从1一直到x都没有浓雾,则视野为 INF;

其他情况下,位置x的视野定义为max(R-L+1),其中L≤x≤R,∀y∈[L,R],位置y没有浓雾。

具体来说,会有以下事件发生:

1 L R :位置[L,R]产生浓雾;

2 L R :位置[L,R]浓雾消散;

3 x :询问位置x的视野。

一开始,小路上没有任何浓雾。


输入

第一行包含一个整数S。

第二行包含一个整数Q,表示事件总数。

接下来Q行,每行描述一个事件。


输出

对于每个询问事件,输出一行一个整数或字符串”INF”(不含引号)。

样例输入 Copy

5

5

1 2 4

3 1

3 4

2 3 3

3 3

样例输出 Copy

INF

0

1

提示

对于40%的数据,S×Q≤5×10^7。

对于100%的数据,2≤S≤10^5 , 2≤Q≤ 2×10^5,1≤L≤R≤S,1≤x≤S。

思路:

区间修改果断线段树。

这个题查询的地方很巧妙,定义的最大视野是分别向左向右到达的没有浓雾的最远距离。

假设这一点有浓雾,那就输出0;如果没有浓雾,那么在分别向左向右延伸的一段区间肯定也没有浓雾;综上,可以二分分别查找左右的最大边界。

具体细节见代码吧~

代码:

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int, int> PII;
#define I_int ll
#define PI 3.1415926535898
inline ll read()
{
    ll x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
char F[200];
inline void out(I_int x) {
    if (x == 0) return (void) (putchar('0'));
    I_int tmp = x > 0 ? x : -x;
    if (x < 0) putchar('-');
    int cnt = 0;
    while (tmp > 0) {
        F[cnt++] = tmp % 10 + '0';
        tmp /= 10;
    }
    while (cnt > 0) putchar(F[--cnt]);
    puts("");
}
const int maxn=1e6+7;
int n,m;
int v,l,r;
struct node{
    int l,r;///左右边界
    int lazy;///懒标记
    int st;//0表示没有浓雾,1表示有浓雾
}a[maxn*4];
void pushup(int u){
    a[u].st=a[u<<1].st|a[u<<1|1].st;//当两个子节点都没都浓雾时才没有浓雾
}
void pushdown(int u){
    auto &root=a[u],&left=a[u<<1],&right=a[u<<1|1];
    if(root.lazy!=-1){
        left.lazy=right.lazy=left.st=right.st=root.lazy;
        root.lazy=-1;
    }
}
void build(int u,int l,int r){
    a[u].l=l,a[u].r=r;
    if(l==r){
        a[u].lazy=a[u].st=0;///初始都没有浓雾
    }
    else{
        int mid=(l+r)>>1;
        build(u<<1,l,mid);build(u<<1|1,mid+1,r);
        pushup(u);
    }
}
void update(int u,int l,int r,int ll,int rr,int v){
    if(l>r||r<ll||l>rr) return ;///完全不包含
    if(l>=ll&&r<=rr){//完全包含
        a[u].st=v;
        a[u].lazy=v;
    }
    else{
        int mid=(l+r)>>1;
        pushdown(u);//传递懒惰标记
        update(u<<1,l,mid,ll,rr,v);//更新左右子树
        update(u<<1|1,mid+1,r,ll,rr,v);
        pushup(u);
    }
}
int query(int u,int l,int r,int ll,int rr){
    if(l>r||r<ll||l>rr) return 0;///完全不包含
    if(l>=ll&&r<=rr) return a[u].st;///完全包含
    int mid=(l+r)>>1;
    pushdown(u);//传递懒惰标记
    int resl=query(u<<1,l,mid,ll,rr),resr=query(u<<1|1,mid+1,r,ll,rr);
    if(rr<=mid) return resl;///完全在左子树
    if(ll>mid) return resr;//完全在右子树
    return (resl|resr);
}
void solve(int x){
    int xx=query(1,1,n,x,x);
    if(xx){//x处有浓雾
        puts("0");
        return ;
    }
    int lx=query(1,1,n,1,x);//从1-x一直没有浓雾
    if(lx==0){
        puts("INF");
        return ;
    }
    int rx=query(1,1,n,x,n);
    if(rx==0){
        puts("INF");
        return ;
    }
    int l=1,r=x,resl=x;
    ///在1-x内 二分找左边的最远视野
    while(l<=r){
        int mid=(l+r)>>1;
        if(query(1,1,n,mid,x)==0){//mid-x一直没浓雾
            resl=mid,r=mid-1;//继续往左找左边界
        }
        else l=mid+1;
    }
    l=x,r=n;int resr=x;
    while(l<=r){
        int mid=(l+r)>>1;
        if(query(1,1,n,x,mid)==0){//x-mid没有浓雾,继续向右寻找右边界
            resr=mid,l=mid+1;
        }
        else r=mid-1;
    }
    out(resr-resl+1);
   // cout<<<<endl;
}
int main(){
    n=read();m=read();
    build(1,1,n);
    while(m--){
        v=read();
        if(v==1){
            l=read();r=read();
            update(1,1,n,l,r,1);///产生浓雾
        }
        else if(v==2){
            l=read();r=read();
            update(1,1,n,l,r,0);///消散浓雾
        }
        else{
            int x;x=read();///查询视野
            solve(x);
        }
    }
    return 0;
}

感觉就是个板子题但是写了一个多小时。。

看网上还有用珂朵莉树过的,真·奇奇怪怪的数据结构:传送门


目录
相关文章
codeforces 272C. Dima and Staircase(线段树)
题目很长,看加猜加谷歌翻译才看懂了题目。每级台阶的宽都是1,但高不同,并且告诉你了,然后给你m个箱子,长和宽都告诉你,把箱子靠左放,求箱子的底部有多高。
32 0
PTA猴子选大王(约瑟夫环问题)
PTA猴子选大王(约瑟夫环问题)
133 1
|
算法
二分&三分
二分&三分
157 0
二分&三分
UPC-喜爱(打表+二分)
UPC-喜爱(打表+二分)
99 0
UPC-喜爱(打表+二分)
|
定位技术
宝岛探险(求岛屿大小,染色法) 宽搜 深搜
宝岛探险(求岛屿大小,染色法) 宽搜 深搜
宝岛探险(求岛屿大小,染色法) 宽搜 深搜
|
人工智能 Java
HDU-敌兵布阵(线段树 || 树状数组)
HDU-敌兵布阵(线段树 || 树状数组)
96 0
|
人工智能 BI
UPC Decayed Bridges(并查集+思维)
UPC Decayed Bridges(并查集+思维)
106 0
HDU-致命武器(线段树)
HDU-致命武器(线段树)
92 0
每日一题之20201103(941. 有效的山脉数组)
首先要弄清楚题目的意图,曾经在字节面试遇到过类似的题目,但那题是需要找出这个峰值。 所以解法也肯定不一样。 官方给的题解是直接遍历,我们这里采用双指针分别从头和尾往中间遍历,如果山脉符合要求,那么2个指针会停在同一个山脉。
每日一题之20201103(941. 有效的山脉数组)