hdu 1540 线段树区间合并

题意:

1~n按顺序排列的n个数字,有三种操作:

1. D x 把第x个数摧毁。

2. Q x 询问第x个数所在的最长无摧毁数的连续长度。

3. R 把把上一个摧毁的数复原。

题解:

1.区间合并:sum[num]存储num结点对应的区间[l , r]的最大无摧毁数的连续长度

sum_l[num]存储num结点对应的区间[l , r]的包括l在内的最大无摧毁数的连续长度

sum_r[num]存储num结点对应的区间[l , r]的包括r在内的最大无摧毁数的连续长度

具体细节体现在代码中,不好叙述,重点是区间合并!!!

#include<bits/stdc++.h>
#define N 50005
#define inf 0x3f3f3f3f
using namespace std ;
int n , m ;
int x ;
int sum[N << 2] ;
int sum_l[N << 2] ;
int sum_r[N << 2] ;
void build(int l , int r , int num) //把3个数组初始化
{
    int lson = num * 2 , rson = num * 2 + 1 ;
    int mid = (l + r) / 2 ;
    if(l == r)
    {
        sum[num] = sum_l[num] = sum_r[num] = 1 ;
        return ;
    }
    build(l , mid , lson) ;
    build(mid + 1 , r , rson) ;
    sum[num] = sum_l[num] = sum_r[num] = r - l + 1 ;
}
void update(int l , int r , int num , int k)
{
    int lson = num * 2 , rson = num * 2 + 1 ;
    int mid = (l + r) / 2 ;
    if(l == x && x == r)
    {
        if(k == 0) // 摧毁
          sum[num] = sum_l[num] = sum_r[num] = 0 ;
        else //复原
          sum[num] = sum_l[num] = sum_r[num] = 1 ;
        return ;
    }
    if(x <= mid) //假如x在左子树
       update(l , mid , lson , k) ;
    else //假如x在右子树
       update(mid + 1 , r , rson , k) ;
    sum_l[num] = sum_l[lson] ; //初始化
    sum_r[num] = sum_r[rson] ; //初始化
    sum[num] = max(max(sum[lson] , sum[rson]) , sum_r[lson] + sum_l[rson]) ;
    //当前结点对应区间的最大长度为左子树的最大长度、右子树的最大长度、左子树的右端点和右子树的左端点拼接的最大长度
    if(sum[lson] == mid - l + 1) // 若左子树满,则当前结点加上右子树的区间左端点开始的连续长度
       sum_l[num] += sum_l[rson] ;
    if(sum[rson] == r - mid) // 若右子树满,则当前结点加上左子树的区右端点开始的连续长度左区间
       sum_r[num] += sum_r[lson] ;
}
int query(int l , int r , int num , int t)
{
    int lson = num * 2 , rson = num * 2 + 1 ;
    int mid = (l + r) / 2 ;
    if(l == r || sum[num] == 0 || sum[num] == r - l + 1) //无需往下递归
        return sum[num] ;
    if(t <= mid)//假如t在左子树
    {
         //t在左子树的右端点的最大连续长度内,需要与右子树拼接,
         //最多拼接两棵树的原因是多于两棵的子树也会成对拼接
        if(t >= mid - sum_r[lson] + 1)
           return query(l , mid , lson , t) + query(mid + 1 , r , rson , mid + 1) ;
        else
           return query(l , mid , lson , t) ;
    }
    else
    {
        if(t <= mid + sum_l[rson]) //同理
           return query(mid + 1 , r , rson , t) + query(l , mid , lson , mid) ;
        else
           return query(mid + 1 , r , rson , t) ;
    }
}
int main()
{
    char s1[10] ;
    stack <int> s ;
    while(scanf("%d%d" , &n , &m) != EOF)
    {
      build(1 , n , 1) ;
      while(m --)
      {
        scanf("%s" , s1) ;
        if(s1[0] == 'D')
        {
           scanf("%d" , &x) ;
           update(1 , n , 1 , 0) ;
           s.push(x) ;
        }
        else if(s1[0] == 'Q')
        {
           scanf("%d" , &x) ;
           printf("%d\n" , query(1 , n , 1 , x)) ;
        }
        else //复原上一个数很明显是用栈
        {
           x = s.top() ;
           s.pop() ;
           update(1 , n , 1 , 1) ;
        }
      }
    }
}

猜你喜欢

转载自blog.csdn.net/Irving0323/article/details/88367578