线段树 (ICPC小米预赛第一场 EPhone Network )

Posted Kalzn

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段树 (ICPC小米预赛第一场 EPhone Network )相关的知识,希望对你有一定的参考价值。

题目链接
题意:给你一个1到n的数组。元素取值是[1, m]。对于1到m的每一个i。你要回答出至少包含[1,i]的所有元素各一次的最小区间长度。
题解:距离出线只差一题。队友在搞G题构造,我在搞这个。最后没出。没办法。一看题解,发现真的只差一步就搞出来了:vector存入1到m的每个数字的位置序列。想到了。线段数维护每个点作为左端点时的最近右端点。想到了。从[1,i]递推[1,i+1],因为这个数值单调可以二分寻找赋值。也想到了。最后一步通过最近右端点怎么维护最小区间长度,愣是没想到。很骚的是,题解也一笔带过了!而最骚的是,虽然题解没说怎么维护,但是看完题解不到10秒,我就知道该怎么维护了。 woc,真的魔幻啊。我自己都觉得我是个演员。

要说的是,我的这份代码是 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n)的,因为在递推时寻找区间赋值是二分套线段树。很容易就可以想到多维护一个区间最近右端点的最大值,然后可以直接线段树 O ( l o g n ) O(logn) O(logn)查询,使得算法变成题解所说的 O ( n l o g n ) O(nlogn) O(nlogn)。但是1e5数据量,没有卡。本人图方便(懒)就直接二分上了。

下面是ac代码:

// % everyone
#include <cstdio>
#include<iostream>
#include<cstring>
#include <map>
#include <queue>
#include <set>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <vector>
#include <string>
#include <list>
#include <cctype>
#include <time.h>
 
namespace IO 
    double start_time = 0.0;
    void ct()  start_time = clock(); return; 
    void fast_cin()  std::ios::sync_with_stdio(false); std::cin.tie(); 
    void read_f(int flag = 0)  freopen("0.in", "r", stdin); if(!flag) freopen("0.out", "w", stdout); 
    void run_time()  std::cout << "\\nESC in : " << ( clock() - start_time ) * 1000.0 / CLOCKS_PER_SEC << "ms" << std::endl; 

using namespace IO;
template <typename T>
bool bacmp(const T & a, const T & b)  return a > b; 
template <typename T>
bool pecmp(const T & a, const T & b)  return a < b; 
 
#define ll long long
#define ull unsigned ll
#define _min(x, y) ((x)>(y)?(y):(x))
#define _max(x, y) ((x)>(y)?(x):(y))
#define max3(x, y, z) ( max( (x), max( (y), (z) ) ) )
#define min3(x, y, z) ( min( (x), min( (y), (z) ) ) )
#define pr make_pair
#define pb push_back
using namespace std;

const int N = 2e5+5;
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;

struct Node

    int l, r;
    int val;
    int ans;
    int laz;
 tr[N<<2];
inline void update(int p, int v)

    tr[p].val = v;
    tr[p].ans = v - tr[p].r + 1;
    tr[p].laz = v;

inline void pushup(int p)

    tr[p].val = min(tr[p<<1].val, tr[p<<1|1].val);
    tr[p].ans = min(tr[p<<1].ans, tr[p<<1|1].ans);

inline void spread(int p)

    if (tr[p].laz == 0) return;
    update(p<<1, tr[p].laz);
    update(p<<1|1, tr[p].laz);
    tr[p].laz = 0;

void build(int p, int l, int r)

    tr[p].l = l; tr[p].r = r;
    tr[p].ans = tr[p].laz = tr[p].val = 0;
    if(l == r)
    
        return;
    
    int mid = (l + r) >> 1;
    build(p<<1, l, mid);
    build(p<<1|1, mid+1, r);
    pushup(p);

void change(int p, int l, int r, int v)

    if (l > r) return;
    if (l <= tr[p].l && tr[p].r <= r)
    
        update(p, v);
        return;
    
    spread(p);
    int mid = (tr[p].l + tr[p].r) >> 1;
    if (l <= mid) change(p<<1, l, r, v);
    if (r > mid) change(p<<1|1, l, r, v);
    pushup(p);
    return;

int ask(int p, int x)

    if (tr[p].l == tr[p].r) return tr[p].val;
    int mid = (tr[p].l + tr[p].r) >> 1;
    spread(p);
    if (x <= mid) return ask(p<<1, x);
    else return ask(p<<1|1, x);

vector<int> num[N];
int che(int l, int r)

    int gg = r;
    while(l <= r)
    
        int mid = (l + r) >> 1;
        if (ask(1, mid) < gg) l = mid+1;
        else r = mid-1;
    
    return l-1;

int main()

    int n, m;
    cin >> n >> m;
    build(1, 1, n);
    for (int i = 1; i <= m; i++) num[i].pb(0);
    for (int i = 1; i <= n; i++)
    
        int te; scanf("%d", &te);
        num[te].pb(i);
    
    for (int i = 1; i <= m; i++)
    
       // cout << i << " ::: " << endl;
        for (int  j = 1; j < num[i].size(); j++)
        
            int p = che(num[i][j-1]+1, num[i][j]);
            change(1, num[i][j-1]+1, p, num[i][j]);
        
        change(1, *num[i].rbegin()+1, n, inf);
        
        // for (int i = 1; i <= n; i++)
        // 
        //     cout << ask(1, i) << " ";
        // 
        // cout << endl;
        printf("%d ", tr[1].ans);
    
    return 0;

以上是关于线段树 (ICPC小米预赛第一场 EPhone Network )的主要内容,如果未能解决你的问题,请参考以下文章

二分/贪心(ICPC小米预赛第一场 A 2020)

ACM-ICPC 2018 南京赛区网络预赛 Lpl and Energy-saving Lamps 线段树

ACM-ICPC 2018 南京赛区网络预赛 G Lpl and Energy-saving Lamps(线段树)

[计蒜客] ACM-ICPC 2018 南京赛区网络预赛 | 部分题解 | 线段树 + 线性筛 + 最短路

ACM-ICPC 2018 徐州赛区网络预赛 H. Ryuji doesn't want to study (线段树)

ACM-ICPC 2018 南京赛区网络预赛 G. Lpl and Energy-saving Lamps (弱线段树)