poj 3368 Frequent values(线段树)

不会做,看了别人的想法 做的
详见原文 http://blog.sina.com.cn/s/blog_6635898a0100kzpx.html

#include <stdio.h>
#define M 100005

struct data
{
      int l,r,max;
}node[3*M];
struct da
{
      int start,end;
}seg[M];

int num[M],hash[M];
int Max (int a,int b)
{
      return a > b?a:b;
}
void C_Tree (int left,int right,int u)
{
      node[u].l = left;
      node[u].r = right;
      if (left == right)
      {
              node[u].max = seg[left].end - seg[left].start + 1;
              return ;
      }
      int mid = (left + right)>>1;
      C_Tree (left,mid,u<<1);
      C_Tree (mid+1,right,(u<<1)+1);
      node[u].max = Max (node[u<<1].max,node[(u<<1)+1].max);
}

int query (int left,int right,int u)
{
      if (node[u].l == left&&node[u].r == right)
              return node[u].max;
      int mid = (node[u].l + node[u].r)>>1;
/
  if (right <= mid)
              return query (left,right,u<<1);
      if (left >= mid + 1)
              return query (left,right,(u<<1)+1);
      int a = query (left,mid,u<<1);
      int b = query (mid+1,right,(u<<1)+1);
//
                                                                    //这样写跟下面的写法有时竟然是一样AC和WA的关系 不明白
      if (right <= mid)                                      //什么原因??
              query (left,right,u<<1);
      else if (left >= mid + 1)
              query (left,right,(u<<1)+1);
      else
      {
              int a = query (left,mid,u<<1);
              int b = query (mid+1,right,(u<<1)+1);
              return Max (a,b);
      }
}
int main ()
{
      int n,m,i,k,loc,a,b;
      while (scanf ("%d",&n)&&n)
      {
              scanf ("%d",&m);
              for (i = 1;i <= n;i ++)
                      scanf ("%d",&num[i]);
              k = 0;
              loc = 100005;
              for (i = 1;i <= n;i ++)
              {
                      if (num[i] != loc)
                      {
                              loc = num[i];
                              seg[++k].start = i;      //seg[] 将相同集合缩成一个点
                              seg[k].end = i;
                      }
                      else
                              seg[k].end = i;
                      hash[i] = k;                            //hash 记录每个i 被seg缩在哪个点内
              }
              C_Tree (1,k,1);
              while (m --)
              {
                      scanf ("%d%d",&a,&b);
                      int k1 = hash[a];
                      int k2 = hash[b];
                      if (k1 == k2)                //如果a b 属于同一个区间,直接相减就得
                              printf ("%d\n",b - a + 1);
                      else                                  //因为a b可能在某个段的中间,分开考虑
                      {
                              int num1 = seg[k1].end - a + 1;          //a所在段的相同数的个数
                              int num2 = b - seg[k2].start + 1;      //b所在段的相同数的个数
                              int num3 = 0;
                              if (k2 - k1 > 1)                                      //k1,k2 相差大于1 查找k1+1到k2-1这区间中最大的集合
                                      num3 = query(k1+1,k2-1,1);
                              printf ("%d\n",Max(Max(num1,num2),num3));//比较
                      }
              }
      }
      return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值