hdu4973 线段树(题目不错,用了点,段,更新查找还有DFS)

题意:
      给你一个初始序列,初始序列长度n,分别为1 2 3 4 5 ....n,有两种操作
(1)D l r 把l_r之间的数据都复制一遍 1 2 3 4 5 6 D 2 4 = 1 2 2 3 3 4 4 5 6
(2)Q l r 询问lr之间的数字出现的最大次数 1 2 2 3 3 4 4 4 5 Q 1 3 = 2


思路:
      这个题目可以用线段树来解决,我们可以建一棵树1--n的,这个题目要注意一点就是无论怎么复制,所有的数字依然是连续的,对于线段树的每一个节点,我们有两个权值,区间元素个数,区间元素出现次数最大值,这样每次遇到一个区间,我们就把这个区间拆成三部分,左边的点,中间部分,右边的一个点,两边的用点更新,中间部分用段更新,每次给一个范围我们就可以根据这个范围找到范围所涉及到的数字范围(1--n),比如

11223344445555 现在给出范围3 13 =则找到的范围是2-5,这样点2,5单独处理,3-4用段更新处理,找的过程中我用的是深搜找的,对于每个点的信息,其实可以再深搜里直接一起找出来,但是我自己当初没想到,直接又多写了一个断询问,虽然麻烦点,但也AC了,具体的看代码吧!


#include<stdio.h>
#include<string.h>

#define lson l ,mid ,t << 1
#define rson mid + 1 ,r ,t << 1 | 1
#define N_node 200000

__int64 sum[N_node] ,max[N_node] ,mark[N_node];

__int64 maxx(__int64 x ,__int64 y)
{
   return x > y ? x : y;
}

void Pushup(__int64 t)
{
   sum[t] = sum[t<<1] + sum[t<<1|1];
   max[t] = maxx(max[t<<1] ,max[t<<1|1]);
}

void Pushdown(__int64 t)
{
   if(mark[t])
   {
      mark[t<<1] += mark[t];
      mark[t<<1|1] += mark[t];
      sum[t<<1] <<= mark[t];
      sum[t<<1|1] <<= mark[t];
      max[t<<1] <<= mark[t];
      max[t<<1|1] <<= mark[t];    
      mark[t] = 0;
   }  
   
}

void BuidTree(__int64 l ,__int64 r ,__int64 t)
{
   max[t] = sum[t] = mark[t] = 0;
   if(l == r)
   {
      max[t] = sum[t] = 1;
      return;
   }
   __int64 mid = (l + r) >> 1;
   BuidTree(lson);
   BuidTree(rson);
   Pushup(t);
}

void Update_1(__int64 l ,__int64 r ,__int64 t ,__int64 a ,__int64 b)
{//点更新 
   if(l == r)
   {
      max[t] += b;
      sum[t] += b;
      return;
   }
   Pushdown(t);
   __int64 mid = (l + r) >> 1;
   if(a <= mid) Update_1(lson ,a ,b);
   else Update_1(rson ,a ,b);
   Pushup(t);
}


void Update_2(__int64 l ,__int64 r ,__int64 t ,__int64 a ,__int64 b)
{//段更新
   if(a <= l && b >= r)
   {
      sum[t] *= 2;
      max[t] *= 2;
      mark[t] ++;
      return;
   }
   Pushdown(t);
   __int64 mid = (l + r) >> 1;
   if(a <= mid) Update_2(lson ,a ,b);
   if(b > mid)  Update_2(rson ,a ,b);
   Pushup(t);
}

__int64 Query_1(__int64 l ,__int64 r ,__int64 t ,__int64 a ,__int64 b)
{//段查找,区间最大值
    if(a <= l && b >= r)
    return max[t];
    Pushdown(t);
    __int64 mid = (l + r) >> 1;
    __int64 now = 0;
    if(a <= mid) now = Query_1(lson ,a ,b);
    if(b > mid)  now = maxx(now ,Query_1(rson ,a ,b));
    return now;
}

__int64 Query_2(__int64 l ,__int64 r ,__int64 t ,__int64 a ,__int64 b)
{//段查找,区间和
    if(a <= l && b >= r) 
    return sum[t];
    Pushdown(t);
    __int64 mid = (l + r) >> 1;
    __int64 now = 0;
    if(a <= mid) now = Query_2(lson ,a ,b);
    if(b > mid) now += Query_2(rson ,a ,b);
    return now;
}

__int64 DFS_Find(__int64 l ,__int64 r ,__int64 t ,__int64 now ,__int64 ss)
{//深搜查找范围所在的点
   if(l == r) return l;
   Pushdown(t);
   __int64 mid = (l + r) >> 1;
   if(now <= sum[t<<1] + ss)return  DFS_Find(lson ,now ,ss);
   else return DFS_Find(rson ,now ,ss + sum[t<<1]);
}

int main ()
{
   int t ,cas = 1 ,n ,m ,i;
   __int64 a ,b;
   char str[5];
   scanf("%d" ,&t);
   while(t--)
   {
      scanf("%d %d" ,&n ,&m);
      BuidTree(1 ,n ,1);
      printf("Case #%d:
" ,cas ++);
      for(i = 1 ;i <= m ;i ++)
      {
         scanf("%s %I64d %I64d" ,str ,&a ,&b);
         __int64 l = DFS_Find(1 ,n ,1 ,a ,0);
         __int64 r = DFS_Find(1 ,n ,1 ,b ,0);
         if(str[0] == 'D')
         {
            if(l == r)
            {
               Update_1(1 ,n ,1 ,l ,b - a + 1);
               continue;
            }
            __int64 ls = Query_2(1 ,n ,1 ,1 ,l) - a + 1;
            __int64 rs = b - Query_2(1 ,n ,1 ,1 ,r - 1);
            Update_1(1 ,n ,1 ,l ,ls);
            Update_1(1 ,n ,1 ,r ,rs);
            if(r - l > 1)
            Update_2(1 ,n ,1 ,l + 1 ,r - 1);
         }
         else
         {
            if(l == r)
            {
               printf("%I64d
" ,b - a + 1);
               continue;
            }
            __int64 now = 0;
            __int64 ls = Query_2(1 ,n ,1 ,1 ,l) - a + 1;
            __int64 rs = b - Query_2(1 ,n ,1 ,1 ,r - 1);         
            if(r - l > 1) now = Query_1(1 ,n ,1 ,l + 1 ,r - 1);
            if(now < ls) now = ls;
            if(now < rs) now = rs;
            printf("%I64d
" ,now);
         }
      }
   }
   return 0;
}

原文地址:https://www.cnblogs.com/csnd/p/12062816.html