Tunnel Warfare 线段树 区间合并|最大最小值

泄露秘密 提交于 2020-01-05 04:14:58

B - Tunnel WarfareHDU - 1540

这个有两种方法,一个是区间和并,这个我个人感觉异常恶心

第二种方法就是找最大最小值  kuangbin——线段树专题 H - Tunnel Warfare <-- 这个博客讲的很清楚

 

#include <cstdio>//法一:最大值最小值法,这个就是每一个点,如果这个点没有被摧毁,那就找到这个点最左边的和最右边的
#include <cstdlib>//最大-最小+1.这个就是这个最大连续长度。
#include <queue>//建树,很简单,主要就是query和update。
#include <algorithm>//这个地方的怎么去找一个包含一个数的一个区间的最大最小值呢?
#include <vector>//这个就是从上面往下面查询的过程中,就去找,如果是找最大值就去max,最小值就取min
#include <cstring>//这个要注意建树,这个区间的最大值的意思是,小于等于这个数的最大的被炸了的村庄,这个就说明,开始最大值为0,因为没有任何一个村庄被炸
#include <string>//区间的最小值,意思是大于等于这个数,被炸了的村庄的最小值,开始为n+1.因为没有村庄被炸。
#include <iostream>
#include <stack>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn = 1e5 + 100;
struct node
{
    int l, r;
    int mx, mn;
}tree[maxn*4];
int n;
void build(int id,int l,int r)
{
    tree[id].l = l;
    tree[id].r = r;
    if(l==r)
    {
        tree[id].mn = n+1;
        tree[id].mx = 0;
        return;
    }
    int mid = (l + r) >> 1;
    build(id << 1, l, mid);
    build(id << 1 | 1, mid + 1, r);
    tree[id].mx = max(tree[id << 1].mx, tree[id << 1 | 1].mx);
    tree[id].mn = min(tree[id << 1].mn, tree[id << 1 | 1].mn);
}

void update_max(int id,int x,int z)
{
    if(tree[id].l==tree[id].r)
    {
        tree[id].mx = z;
        return;
    }
    int mid = (tree[id].l + tree[id].r) >> 1;
    if(x<=mid) update_max(id << 1, x, z);
    if (x > mid) update_max(id << 1 | 1, x, z);
    tree[id].mx = max(tree[id << 1].mx, tree[id << 1 | 1].mx);
}

void update_min(int id,int x,int z)
{
    if(tree[id].l==tree[id].r)
    {
        tree[id].mn = z;
        return;
    }
    int mid = (tree[id].l + tree[id].r) >> 1;
    if (x <= mid) update_min(id << 1, x, z);
    if (x > mid) update_min(id << 1 | 1, x, z);
    tree[id].mn = min(tree[id << 1].mn, tree[id << 1 | 1].mn);
}

int query_max(int id,int x,int y)
{
    int ans = 0;
    if(x<=tree[id].l&&y>=tree[id].r)
    {
        return tree[id].mx;
    }
    int mid = (tree[id].l + tree[id].r) >> 1;
    if (x <= mid) ans = max(ans, query_max(id << 1, x, y));
    if (y > mid) ans = max(ans, query_max(id << 1 | 1, x, y));
    return ans;
}

int query_min(int id,int x,int y)
{
    int ans = inf;
    if(x<=tree[id].l&&y>=tree[id].r)
    {
        return tree[id].mn;
    }
    int mid = (tree[id].l + tree[id].r) >> 1;
    if (x <= mid) ans = min(ans, query_min(id << 1, x, y));
    if (y > mid) ans = min(ans, query_min(id << 1 | 1, x, y));
    return ans;
}

int main()
{
    
    int m, x;
    while(cin >> n >> m)
    {
        stack<int>sta;
        build(1, 1, n);
        while(m--)
        {
            char s[10];
            scanf("%s", s);
            if(s[0]=='D')
            {
                cin >> x;
                update_max(1, x, x);
                update_min(1, x, x);
                sta.push(x);
            }
            if(s[0]=='R')
            {
                int y = sta.top(); sta.pop();
                update_max(1, y, 0);
                update_min(1, y, n + 1);
            }
            if(s[0]=='Q')
            {
                cin >> x;
                int L = query_min(1, x, n + 1);
                int R = query_max(1, 0, x);
                //printf("%d %d\n", L, R);
                if (L == R) printf("0\n");
                else printf("%d\n", L - R - 1);
            }
        }
    }
    
    return 0;
}
方法一
//法二:区间合并,这个应该更好懂一点,就是维护一下一个区间的前缀后缀长度
//这个更新应该比较简单,
#include <cstdio>
#include <cstdlib>
#include <queue>
#include <algorithm>
#include <vector>
#include <cstring>
#include <string>
#include <iostream>
#include <stack>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn = 1e5 + 100;
struct node
{
    int l, r, len;
    int max_pre, max_last;
}tree[maxn*4];

void push_up(int id)
{
    tree[id].max_pre = tree[id << 1].max_pre;
    tree[id].max_last = tree[id << 1 | 1].max_last;
    if (tree[id << 1].max_pre == tree[id << 1].len)
    {
        tree[id].max_pre += tree[id << 1 | 1].max_pre;
    }
    if(tree[id<<1|1].max_last==tree[id<<1|1].len)
    {
        tree[id].max_last += tree[id << 1].max_last;
    }
}

void build(int id,int l,int r)
{
    tree[id].l = l;
    tree[id].r = r;
    tree[id].len = r - l + 1;
    if(l==r)
    {
        tree[id].max_pre = tree[id].max_last = 1;
        return;
    }
    int mid = (l + r) >> 1;
    build(id << 1, l, mid);
    build(id << 1 | 1, mid + 1, r);
    push_up(id);
}

void update(int id,int x,int z)
{
    if(tree[id].l==tree[id].r)
    {
        tree[id].max_pre = z;
        tree[id].max_last = z;
        return;
    }
    int mid = (tree[id].l + tree[id].r) >> 1;
    if (x <= mid) update(id << 1, x, z);
    else update(id << 1 | 1, x, z);
    push_up(id);
}

int query_pre(int id,int x,int y)
{
    int ans = 0, res = 0;
    if(x<=tree[id].l&&y>=tree[id].r)
    {
        //printf("tree[%d].max_pre=%d\n", id, tree[id].max_pre);
        return tree[id].max_pre;
    }
    //printf("id=%d x=%d y=%d\n", id, x, y);
    int mid = (tree[id].l + tree[id].r) >> 1;
    if (x <= mid) ans=query_pre(id << 1, x, y);
    if (y > mid) res=query_pre(id << 1 | 1, x, y);
    //printf("id=%d ans=%d res=%d mid=%d\n",id, ans, res,mid);
    if (ans >= mid - x + 1)
    {
        //printf("tree[%d].max_pre=%d mid=%d x=%d\n",id, tree[id].max_pre, mid, x);
        ans += res;
    }
    return ans;
}

int query_last(int id,int x,int y)
{
    int ans = 0, res = 0;
    if (x <= tree[id].l&&y >= tree[id].r)
    {
        //printf("tree[%d].last=%d\n", id, tree[id].max_last);
        return tree[id].max_last;
    }
    //printf("id=%d x=%d y=%d\n", id, x, y);
    int mid = (tree[id].l + tree[id].r) >> 1;
    if (x <= mid) ans = query_last(id << 1, x, y);
    if (y > mid) res = query_last(id << 1 | 1, x, y);
    //printf("id=%d mid=%d ans=%d res=%d\n", id, mid,ans, res);
    if (res >= y-mid)
    {
        //printf("tree[%d].max_last=%d  mid=%d x=%d\n",id,tree[id].max_last, mid, x);
        res += ans;
    }
    return res;
}

int main()
{
    int n, m;
    while(scanf("%d %d",&n,&m)!=EOF)
    {
        stack<int>sta;
        build(1, 1, n);
        while(m--)
        {
            char s[10];
            scanf("%s", s);
            if(s[0]=='D')
            {
                int x;
                cin >> x;
                update(1, x, 0);
                sta.push(x);
            }
            if(s[0]=='R')
            {
                int y = sta.top(); sta.pop();
                update(1, y, 1);
            }
            if(s[0]=='Q')
            {
                int x;
                cin >> x;
                int ans = query_pre(1, x, n);
                ans += query_last(1, 1, x);
                if(ans) printf("%d\n", ans-1);
                else printf("0\n");
            }
        }
    }
    return 0;
}
/*
7 10
D 3
D 6
D 5
Q 4
Q 5
R
Q 4
R
Q 4
Q 3
 */
方法二

 

 
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!