2020ICPC·小米 网络选拔赛第一场 E题 Phone Network

题目链接

一、题意

有一个长度为n的正整数序列a。有m个询问。

i个询问是求包括{1,2,...,i}的最小区间长度。

数据范围:1 \leqslant m \leqslant n \leqslant 2 \cdot 10^5

二、题解

我就不班门弄斧了,直接上dls和jls的题解,然后说一下怎么实现这个东西。

同时感谢hdu老哥的code,看这个代码才知道怎么维护R_{i,l}-l+1

维护R_{i,l}需要区间最小值,区间赋值,这个很简单,就是板子,按照题解上说的模拟就行了。

 主要是维护R_{i,l}-l+1。我本来以为是按照区间加等差数列那么维护,未果。

需要定义一个新东西:对于线段树的[l,r]节点,res表示\mathop{min}\limits_{s=l}^{r} R_{i,s}-s+1

\mathop{min}\limits_{s=l}^{r} R_{i,s}-s+1这个东西看起来好像也不是那么好维护,不过再推一下就行了。

\mathop{min}\limits_{s=l}^{r} R_{i,s}-s+1 = lazy - r + 1 , 其中lazy是对[l,r]的区间赋值。

线段树的变化太多了,跪了。

三、代码

#include<bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define sz(x)  (int)x.size()
#define cl(x)  x.clear()
#define all(x)  x.begin() , x.end()
#define rep(i , x , n)  for(int i = x ; i <= n ; i ++)
#define per(i , n , x)  for(int i = n ; i >= x ; i --)
#define mem0(x)  memset(x , 0 , sizeof(x))
#define mem_1(x)  memset(x , -1 , sizeof(x))
#define mem_inf(x)  memset(x , 0x3f , sizeof(x))
#define debug(x)  cerr << #x << " = " << x << '\n'
#define ddebug(x , y)  cerr << #x << " = " << x << "   " << #y << " = " << y << '\n'
#define ios std::ios::sync_with_stdio(false) , cin.tie(0)
using namespace std ;
typedef long long ll ;
typedef long double ld ;
typedef pair<int , int> pii ;
typedef pair<ll , ll> pll ;
typedef double db ;
const int mod = 998244353 ;
const int maxn = 2e5 + 10 ;
const int inf = 0x3f3f3f3f ;
const double eps = 1e-6 ; 
int n , m ;
vector<int> pos[maxn] ;
struct Segment_tree
{
    int l[maxn << 2] , r[maxn << 2] , mn[maxn << 2] , res[maxn << 2] , lazy[maxn << 2] ;
    int ls(int id)
    {
        return id << 1 ;
    }
    int rs(int id)
    {
        return id << 1 | 1 ;
    }
    void build(int id , int L , int R)
    {
        l[id] = L , r[id] = R , mn[id] = 0 , res[id] = inf , lazy[id] = 0 ;
        if(L == R)  return ;
        int mid = (L + R) / 2 ;
        build(ls(id) , L , mid) ;
        build(rs(id) , mid + 1 , R) ;
    }
    void push_down(int id)
    {
        if(lazy[id] == 0)  return ;
        lazy[ls(id)] = lazy[id] ;
        lazy[rs(id)] = lazy[id] ;
        mn[ls(id)] = lazy[id] ;
        mn[rs(id)] = lazy[id] ;
        res[ls(id)] = lazy[id] - r[ls(id)] + 1 ;
        res[rs(id)] = lazy[id] - r[rs(id)] + 1 ;
        lazy[id] = 0 ;
    }
    void push_up(int id)
    {
        mn[id] = min(mn[ls(id)] , mn[rs(id)]) ;
        res[id] = min(res[ls(id)] , res[rs(id)]) ;
    }
    int find(int id , int L , int R)
    {
        if(mn[id] >= R || r[id] < L || l[id] > R)  return -1 ;
        if(l[id] == r[id])  return l[id] ;
        int ans = find(rs(id) , L , R) ;
        if(ans == -1)  ans = find(ls(id) , L , R) ;
        return ans ;
    }
    void modify(int id , int L , int R , int x)
    {
        if(L > R || L > r[id] || R < l[id])  return ; //避免越界。
        if(L <= l[id] && r[id] <= R)
        {
            mn[id] = x ;
            res[id] = x - r[id] + 1 ;
            lazy[id] = x ;
            return ;
        }
        push_down(id) ;
        modify(ls(id) , L , R , x) ;
        modify(rs(id) , L , R , x) ;
        push_up(id) ;
    }
} seg ;
int main()
{
    ios ;
    cin >> n >> m ;
    rep(i , 1 , n)
    {
        int x ;
        cin >> x ;
        pos[x].pb(i) ;
    }
    seg.build(1 , 1 , n) ;
    rep(i , 1 , m)
    {
        int pre = 0 ;
        for(auto now : pos[i])
        {
            int p = seg.find(1 , pre + 1 , now) ;
            if(p != -1)  seg.modify(1 , pre + 1 , p , now) ;
            pre = now ;
        }
        if(pos[i].back() < n)  seg.modify(1 , pos[i].back() + 1 , n , inf) ;
        cout << seg.res[1] << " \n"[i == m] ;
    }
    return 0 ;
}

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值