zoukankan      html  css  js  c++  java
  • 求点所在的最长连续区间

    http://acm.hdu.edu.cn/showproblem.php?pid=1540

    Tunnel Warfare

    Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
    Total Submission(s): 18628    Accepted Submission(s): 7171


    Problem Description
    During the War of Resistance Against Japan, tunnel warfare was carried out extensively in the vast areas of north China Plain. Generally speaking, villages connected by tunnels lay in a line. Except the two at the ends, every village was directly connected with two neighboring ones.

    Frequently the invaders launched attack on some of the villages and destroyed the parts of tunnels in them. The Eighth Route Army commanders requested the latest connection state of the tunnels and villages. If some villages are severely isolated, restoration of connection must be done immediately!
     
    Input
    The first line of the input contains two positive integers n and m (n, m ≤ 50,000) indicating the number of villages and events. Each of the next m lines describes an event.

    There are three different events described in different format shown below:

    D x: The x-th village was destroyed.

    Q x: The Army commands requested the number of villages that x-th village was directly or indirectly connected with including itself.

    R: The village destroyed last was rebuilt.
     
    Output
    Output the answer to each of the Army commanders’ request in order on a separate line.
     
    Sample Input
    7 9 D 3 D 6 D 5 Q 4 Q 5 R Q 4 R Q 4
     
    Sample Output
    1 0 2 4
     
    Source
     
    Recommend
    LL
    题意:n个村庄,m次操作,有三种操作,1、D摧毁该村庄,2、R恢复上一个被摧毁的村庄,3、Q询问该点两边最大未摧毁的村庄之和。
    解法:用栈储存被摧毁的村庄,线段树维护两个值ma,mi最大值与最小值。
    初始更新ma为0 , mi 为n+1.
    摧毁更新ma为x,mi为x
    询问x , 询问1-x的最大值max,询问右边x-n的最小值min , 结果为min- max - 1.
     https://blog.csdn.net/chudongfang2015/article/details/52133243
    //#include <bits/stdc++.h>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <iostream>
    #include <string>
    #include <stdio.h>
    #include <queue>
    #include <stack>
    #include <map>
    #include <set>
    #include <string.h>
    #include <vector>
    #define ME(x , y) memset(x , y , sizeof(x))
    #define SF(n) scanf("%d" , &n)
    #define rep(i , n) for(int i = 0 ; i < n ; i ++)
    #define INF  0x3f3f3f3f
    #define mod 20191117
    #define PI acos(-1)
    using namespace std;
    typedef long long ll ;
    int n , q ;
    char s[10];
    int ma , mi;
    
    struct node
    {
        int l , r , ma , mi ;
    }tree[500009*4];
    
    void build(int l , int r , int root)
    {
        tree[root].l = l , tree[root].r = r ;
        if(l == r)
        {
            tree[root].ma = 0 ;
            tree[root].mi = n + 1;
            return ;
        }
        int mid = (l + r) >> 1;
        build(l , mid , root*2);
        build(mid+1 , r , root*2+1);
        tree[root].ma = max(tree[root*2].ma , tree[root*2+1].ma);
        tree[root].mi = min(tree[root*2].mi , tree[root*2+1].mi);
    }
    
    void update_max(int x , int val , int root)
    {
        if(tree[root].l == tree[root].r)
        {
            tree[root].ma = val ;
            return ;
        }
        int mid = (tree[root].l + tree[root].r) >> 1 ;
        if(x <= mid)
            update_max(x , val , root*2);
        else
            update_max(x , val , root*2+1);
        tree[root].ma = max(tree[root*2].ma , tree[root*2+1].ma);
    }
    
    void update_min(int x , int val , int root)
    {
        if(tree[root].l == tree[root].r)
        {
            tree[root].mi = val ;
            return ;
        }
        int mid = (tree[root].l + tree[root].r) >> 1 ;
        if(x <= mid)
            update_min(x , val , root*2);
        else
            update_min(x , val , root*2+1);
        tree[root].mi = min(tree[root*2].mi , tree[root*2+1].mi);
    }
    
    void query_max(int l , int r , int root)
    {
        if(tree[root].l >= l && tree[root].r <= r)
        {
            ma = max(tree[root].ma , ma);
            return ;
        }
        int mid = (tree[root].l + tree[root].r) >> 1 ;
        if(l <= mid)
            query_max(l , r , root*2);
        if(r > mid)
            query_max(l , r, root*2+1);
    }
    
    void query_min(int l , int r , int root)
    {
        if(tree[root].l >= l && tree[root].r <= r)
        {
            mi = min(tree[root].mi , mi);
            return ;
        }
        int mid = (tree[root].l + tree[root].r) >> 1 ;
        if(l <= mid)
            query_min(l , r , root*2);
        if(r > mid)
            query_min(l , r, root*2+1);
    }
    
    int main()
    {
    
        while(~scanf("%d%d" , &n , &q))
        {
            build(1 , n , 1);
            stack<int>st;
            for(int i = 0 ; i < q ; i++)
            {
                scanf("%s" , s);
                if(s[0] == 'D')
                {
                    int x ;
                    scanf("%d" , &x);
                    st.push(x);
                    update_max(x , x , 1);
                    update_min(x , x , 1);
                }
                else if(s[0] == 'R')
                {
                    int x ;
                    if(!st.empty())
                    {
                        x = st.top();
                        update_max(x , 0 , 1);
                        update_min(x , n+1, 1);
                        st.pop();
                    }
                    else{
                        continue ;
                    }
                }
                else{
                    int x ;
                    scanf("%d" , &x);
                    ma = -INF , mi = INF ;
                    query_max(1 , x , 1);
                    query_min(x , n , 1);
                    if(mi != ma)
                        printf("%d
    " , mi - ma - 1);
                    else{
                        printf("0
    ");
                    }
    
                }
            }
        }
    
    
        return 0;
    }
    
    //#include <bits/stdc++.h>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <iostream>
    #include <string>
    #include <stdio.h>
    #include <queue>
    #include <stack>
    #include <map>
    #include <set>
    #include <string.h>
    #include <vector>
    #define ME(x , y) memset(x , y , sizeof(x))
    #define SF(n) scanf("%d" , &n)
    #define rep(i , n) for(int i = 0 ; i < n ; i ++)
    #define INF  0x3f3f3f3f
    #define mod 20191117
    #define PI acos(-1)
    #define gcd __gcd
    using namespace std;
    typedef long long ll ;
    char s[10];
    
    struct node
    {
        int l , r , ll , rr , val;//最大左连续,最大右连续,最大连续
    }tree[50009*4];
    
    void build(int l , int r , int root)
    {
        tree[root].l = l , tree[root].r = r , tree[root].ll = tree[root].rr = tree[root].val = r - l + 1;//初始化为区间长
        if(l == r)
        {
            return ;
        }
        int mid = (l + r) >> 1 ;
        build(l , mid , root*2);
        build(mid+1 , r , root*2+1);
    }
    
    void update(int x , int val , int root)
    {
        if(tree[root].l == tree[root].r)
        {
            tree[root].ll = tree[root].rr = tree[root].val = val ;//将该点左连续、右连续、最长连续更新为val
            return ;
        }
        int mid = (tree[root].l + tree[root].r) >> 1;
        if(x <= mid)
            update(x , val , root*2);
        else
            update(x , val , root*2+1);
        //回溯给父节点赋值
        if(tree[root*2].r - tree[root*2].l + 1 == tree[root*2].ll)//如果(左儿子的左连续)等于(左儿子的区间长)
            tree[root].ll = tree[root*2].ll + tree[root*2+1].ll ;//父节点的左连续等于(左儿子的左连续)加(右儿子的左连续)
        else{
            tree[root].ll = tree[root*2].ll ;//否则,(父节点的左连续)等于(左儿子的左连续)
        }
        if(tree[root*2+1].r - tree[root*2+1].l + 1 == tree[root*2+1].rr)//(父节点右连续)同理(父节点左连续)
            tree[root].rr = tree[root*2+1].rr + tree[root*2].rr ;
        else{
            tree[root].rr = tree[root*2+1].rr ;
        }
        tree[root].val = max(max(tree[root*2].ll , tree[root*2+1].rr) , tree[root*2].rr + tree[root*2+1].ll);//父节点最长连续等于三者最大(左儿子的左连续、右儿子的右连续、(左儿子的右连续)加上(右儿子的左连续))
    }
    
    int query(int x , int root)
    {
        if(tree[root].l == tree[root].r || tree[root].val == 0 || tree[root].r - tree[root].l + 1 == tree[root].val)//如果为叶子节点、最长区间为0,区间长等于最长区间。返回最长区间值
            return tree[root].val ;
        int mid = (tree[root].l + tree[root].r) >> 1 ;
        if(x <= mid)//目标在左儿子
        {
            if(x >= tree[root*2].r - tree[root*2].rr + 1)//目标在左儿子的右连续区间
                return tree[root*2].rr + tree[root*2+1].ll ;//返回左儿子的右连续区间和右儿子的左连续区间
            else{
                return query(x , root*2);//不在右连续区间,递归左儿子
            }
        }
        else{//目标在右儿子
            if(x <= tree[root*2+1].l + tree[root*2+1].ll - 1)//在右儿子的左区间
                return tree[root*2].rr + tree[root*2+1].ll ;//返回右儿子的左连续和左儿子的右连续
            else{
                return query(x , root*2+1);//递归右儿子
            }
        }
    }
    
    int main()
    {
        int n , m ;
        while(~scanf("%d%d" , &n , &m))
        {
            build(1 , n , 1);
            stack<int>st;
            for(int i = 0 ; i < m ; i++)
            {
                scanf("%s" , s);
                if(s[0] == 'D')
                {
    
                    int x ;
                    scanf("%d" , &x);
                    update(x , 0 , 1);
                    st.push(x);
                }
                else if(s[0] == 'R')
                {
                    int x = st.top();
                    update(x , 1 , 1);
                    st.pop();
                }
                else{
                    int x ;
                    scanf("%d" , &x);
                    printf("%d
    " , query(x , 1));
                }
            }
        }
    
    
        return 0;
    }
    
  • 相关阅读:
    设计模式-1.12备忘录模式
    设计模式-简介
    设计模式-1.9享元模式
    设计模式-1.8组合模式
    设计模式-1.7外观模式
    设计模式-1.6建造者模式(生成器模式)
    设计模式-1.5原型模式
    我在GitHubPage的博客
    奇怪的友链增加啦!
    SSL-OI夏日合宿 杂题 LOJ#6089小Y的背包计数问题 根号分治
  • 原文地址:https://www.cnblogs.com/nonames/p/11607997.html
Copyright © 2011-2022 走看看