[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\n", 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:\n", 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\n", 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("\n");
    }
}

 

 

 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:\n", 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\n", 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啊啊啊啊啊啊啊
    }
}

 

 

 

 

 

 

 

 

 

posted @ 2020-10-09 02:56  .Ivorelectra  阅读(102)  评论(0编辑  收藏  举报