• [kuangbin带你飞]专题七 线段树


    D - Mayor's posters || 覆盖型线段树 & 离散化

    https://vjudge.net/contest/399540#problem/D

    对于每个结点,若tree == 0,表示这段区间内颜色不唯一;若tree != 0,这个数字就表示这段区间对应的颜色;

     贴n张海报,即n次区间更新update,最终最多能看到n种颜色。1次整个区间查询query。

    mark[i] == 1表示能看到第i种颜色,mark[i] == 0表示看不到第i种颜色。

    1 <= li <= ri <= 1e7,线段树需要维护的区间过大,数组也要开的很大,会TLE或MLE,需要离散化

    1 <= n <= 10000,最多有1e4张海报,最多有2e4个点,所以离散化后的区间为[1, 20000]

    #include <cstdio>
    #include <string>
    #include <iostream>
    #include <algorithm> using namespace std; typedef long long ll; const int maxn=2e5+4; int arr[maxn], _left[maxn], _right[maxn], tree[maxn<<2], lazy[maxn<<2], mark[100005]; void push_down(int node) { if(lazy[node]) { tree[2 * node] = tree[node]; tree[2 * node + 1] = tree[node]; lazy[2 * node] = lazy[node]; lazy[2 * node + 1] = lazy[node]; lazy[node] = 0; } } void query(int node, int l, int r) { if(l == r || tree[node]) { mark[tree[node]] = 1; return; } push_down(node); int mid = (l + r) / 2; query(node * 2, l, mid); query(node * 2 + 1, mid + 1, r); } void update(int node, int l, int r, int x, int y, ll c) { if(x <= l && y >= r) { tree[node] = c; lazy[node] = c; return; } push_down(node); int mid = (l + r) / 2; if(x <= mid) update(node * 2, l, mid, x, y, c); if(y > mid) update(node * 2 + 1, mid + 1, r, x, y, c); if(tree[node*2] == tree[node*2+1]) tree[node] = tree[node*2]; else tree[node] = 0; } int main() { int n, m, x, y, t; scanf("%d", &t); while(t--) { scanf("%d", &n); fill(mark + 1, mark + 1 + n, 0); for(int i = 1; i <= n; i++) { scanf("%d %d", &_left[i], &_right[i]); arr[i*2-1] = _left[i], arr[i*2] = _right[i]; } sort(arr + 1, arr + 1 + 2 * n); int cnt = unique(arr + 1, arr + 1 + 2 * n) - (arr + 1); fill(tree + 1, tree + 1 + cnt * 4, 0); fill(lazy + 1, lazy + 1 + cnt * 4, 0); for(int i = 1; i <= n; ++i) { int x = lower_bound(arr + 1, arr + 1 + cnt, _left[i]) - arr; int y = lower_bound(arr + 1, arr + 1 + cnt, _right[i]) - arr; update(1, 1, cnt, x, y, i); } query(1, 1, cnt); int ans = 0; for(int i = 1; i <= n; i++) ans += mark[i]; printf("%d ", ans); } }

    H - Can you answer these queries?

    https://vjudge.net/contest/399540#problem/H

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    typedef long long ll;
    const int maxn = 1e5 + 4;
    
    ll arr[maxn], tree[maxn<<2], lazy[maxn<<2];
    bool mark[maxn<<2];
    
    void build(int node, int l, int r)
    {
        if(l == r) {tree[node] = arr[l]; return;}
        int mid = (l + r) / 2;
        build(node * 2, l, mid);
        build(node * 2 + 1, mid + 1, r);
        tree[node] = tree[node * 2] + tree[node * 2 + 1];
    }
    
    ll query(int node, int l, int r, int x, int y)
    {
        if(x <= l && y >= r) return tree[node];
        ll ans = 0; int mid = (l + r) / 2;
        if(x <= mid) ans += query(node * 2, l, mid, x, y);
        if(y > mid) ans += query(node * 2 + 1, mid + 1, r, x, y);
        return ans;
    }
    
    void update(int node, int l, int r, int x, int y)
    {
        if(l == r)
        {
            tree[node] = (ll)sqrt(tree[node]);
            if(tree[node] == 1) mark[node] = 1;
            return;
        }
        if(mark[node] == 1) return;
        int mid = (l + r) / 2;
        if(x <= mid) update(node * 2, l, mid, x, y);
        if(y > mid) update(node * 2 + 1, mid + 1, r, x, y);
        tree[node] = tree[node * 2] + tree[node * 2 + 1];
        mark[node] = mark[node * 2] && mark[node * 2 + 1];
    }
    
    int main()
    {
        int n, m, d, x, y;
        int q = 1;
        while(~scanf("%d", &n))
        {
            memset(mark, 0, sizeof(mark));
            printf("Case #%d:
    ", q);
            for(int i = 1; i <= n; ++i) scanf("%lld", &arr[i]);
            build(1, 1, n);
            scanf("%d", &m);
            for(int i = 0; i < m; ++i)
            {
                scanf("%d %d %d", &d, &x, &y);
                if(x > y) swap(x, y);
                if(d) printf("%lld
    ", query(1, 1, n, x, y));
                else update(1, 1, n, x, y);
            }
            fill(tree + 1, tree + 1 + 4 * n, 0);
            fill(lazy + 1, lazy + 1 + 4 * n, 0);
            ++q;
            printf("
    ");
        }
    }

     J - Assign the task || 覆盖型线段树 & dfs序

    https://vjudge.net/contest/399540#problem/J

    多组数据vector清空!!!

    用dfs序转化成区间,dfs序就是arr,对arr的连续区间操作使用线段树

    L[x], R[x]表示x节点对应的区间左端和右端,相当于arr的下标(虽然这道题arr没用

    注意题目中分配的任务可以为0,所以tree和lazy应该初始化为-1

    eg.

                2

            /      

           3        5

         /      

       4      1   

    L[2] = 1,  R[2] = 5;

    L[3] = 2,  R[3] = 4;

    L[4] = 3,  R[4] = 3;

    L[1] = 4,   R[1] = 4;

    L[5] = 5,  R[5] = 5;

    1 2 3 4 5

    2 3 4 1 5

    #include <cstdio>
    #include <vector>
    using namespace std;
    const int maxn = 5e4 + 3;
    typedef long long ll;
    
    ll tree[maxn<<2], lazy[maxn<<2];
    
    vector<int> G[maxn];
    bool boss[maxn];
    int cur;
    int L[maxn], R[maxn];
    
    void dfs(int x)
    {
        L[x] = ++cur;
        for(int i = 0; i < G[x].size(); ++i)
        {
            dfs(G[x][i]);
        }
        R[x] = cur;
    }
    
    void push_down(int node)
    {
        if(lazy[node] != -1)
        {
            tree[2 * node] = lazy[node];
            tree[2 * node + 1] = lazy[node];
            lazy[2 * node] = lazy[node];
            lazy[2 * node + 1] = lazy[node];
            lazy[node] = -1;
        }
    }
    
    ll query(int node, int l, int r, int x, int y)
    {
        if(x <= l && y >= r) return tree[node];
        push_down(node);
        ll ans = 0L; int mid = (l + r) / 2;
        if(x <= mid) ans = query(node * 2, l, mid, x, y);
        if(y > mid) ans = query(node * 2 + 1, mid + 1, r, x, y);
        return ans;
    }
    
    void update(int node, int l, int r, int x, int y, ll c)
    {
        if(x <= l && y >= r)
        {
            tree[node] = c;
            lazy[node] = c;
            return;
        }
        push_down(node);
        int mid = (l + r) / 2;
        if(x <= mid) update(node * 2, l, mid, x, y, c);
        if(y > mid) update(node * 2 + 1, mid + 1, r, x, y, c);
    
        if(tree[node*2] == tree[node*2+1]) tree[node] = tree[node * 2];
        else tree[node] = -1;
    }
    
    int main()
    {
        int t;
        scanf("%d", &t);
        for(int q = 1; q <= t; ++q)
        {
            printf("Case #%d:
    ", q);
            cur = 0;
            int n, x, y, m;
            char c;
            scanf("%d", &n);
            fill(boss + 1, boss + 1 + n, 0);
            for(int i = 0; i < n-1; ++i)
            {
                scanf("%d %d", &x, &y);
                G[y].push_back(x);
                boss[x] = 1;
            }
            int root;
            fill(lazy + 1, lazy + 1 + 4 * n, -1);
            fill(tree + 1, tree + 1 + 4 * n, -1);
            for(int i = 1; i <= n; ++i)
            {
                if(!boss[i])//找到根节点
                {
                    root = i;
                    break;
                }
            }
            scanf("%d", &m);
            dfs(root);
            for(int i = 0; i < m; ++i)
            {
                scanf(" %c", &c);
                if(c =='C')
                {
                    scanf("%d", &x);
                    printf("%lld
    ", query(1, 1, n, L[x], L[x]));
                }
                else
                {
                    scanf("%d %d", &x, &y);
                    update(1, 1, n, L[x], R[x], y);
                }
            }
            for(int i = 1; i <= n; ++i) G[i].clear();//一直MLE啊啊啊啊啊啊啊
        }
    }
  • 相关阅读:
    蛙蛙推荐:五分钟搞定网站前端性能优化
    蛙蛙推荐:AngularJS学习笔记
    蛙蛙推荐:如何实时监控MySql状态
    这6种思维,学会了你就打败了95%文案!zz
    10分钟,解决卖点没创意的难题zz
    总感觉自己工作沟通想问题时没有逻辑,这可怎么办?| 极简逻辑指南
    「零秒思考」是个神话,不过这款笔记术你值得拥有zz
    关于提高沟通能力的书单 | 章鱼书单zz
    日常沟通的 3 种模式zz
    关于提高沟通能力的书单zz
  • 原文地址:https://www.cnblogs.com/Maxx-el/p/13783510.html
Copyright © 2020-2023  润新知