hdu 3648 Median Filter

本文介绍如何使用树状数组解决求以一点为中心、边长为2*r+1的正方形的中位数问题。通过S型路径减少时间复杂度,实现高效的查找并更新操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

/*

这题就是求以一个点为中心,边长为2*r+1的正方形的中位数,需要用树状数组求。

查完一个中位数后向边上移求下一个,走 s型,才能减少时间。每次树状数组里删去移除的,加上移入的

注意:树状数组输入不能为0,不然会无限循环;这题输出每行最后要有空格,不然PE(这个我觉的它太水了。。)

*/

#include <stdio.h>
#include <string.h>
#define lowbit(x) x&(-x)
int n,r,a[505][505],b[505][505],c[1000001],max,mm;
void add(int x,int val)
{
   while(x<=max+1)
   {
      c[x]+=val;
      x+=lowbit(x);
   }
}
int sum(int x)
{
   int s=0;
   while(x>0)
   {
      s+=c[x];
      x-=lowbit(x);
   }
   return s;
}
int find()
{
   int l,r,mid;
   l=0,r=max+1;
   while(l<r)
   {
      mid=(r+l)/2;
      if(sum(mid)>=mm)
      r=mid;
      else
      l=mid+1;
   }
   return l-1;
}
int main()
{
    while(scanf("%d %d",&n,&r)!=EOF)
    {
      if(n==0&&r==0)
      break;
      int i,j,k;
      max=-1;
      mm=((2*r+1)*(2*r+1)+1)/2;
      memset(c,0,sizeof(c));
      for(i=0;i<n;i++)
      for(j=0;j<n;j++)
      {
         scanf("%d",&a[i][j]);
         if(a[i][j]>max)
         max=a[i][j];
      }
      for(i=0;i<=2*r;i++)
      for(j=0;j<=2*r;j++)
      add(a[i][j]+1,1);
      b[r][r]=find();
      for(i=r;i<n-r;i=i+2)
      {
         if(i!=r)
         {
            for(j=0;j<=2*r;j++)
            add(a[i-r-1][j]+1,-1);
            for(j=0;j<=2*r;j++)
            add(a[i+r][j]+1,1);
            b[i][r]=find();
         }
         for(j=r+1;j<n-r;j++)
         {
            for(k=i-r;k<=i+r;k++)
            add(a[k][j-r-1]+1,-1);
            for(k=i-r;k<=i+r;k++)
            add(a[k][j+r]+1,1);
            b[i][j]=find();
         }
         if(i+1==n-r)
         break;
         for(j=n-2*r-1;j<=n-1;j++)
         add(a[i-r][j]+1,-1);
         for(j=n-2*r-1;j<=n-1;j++)
         add(a[i+r+1][j]+1,1);
         b[i+1][n-r-1]=find();
         for(j=n-r-2;j>=r;j--)
         {
            for(k=i-r+1;k<=i+r+1;k++)
            add(a[k][j+r+1]+1,-1);
            for(k=i-r+1;k<=i+r+1;k++)
            add(a[k][j-r]+1,1);
            b[i+1][j]=find();
         }
      }
      for(i=r;i<n-r;i++)
      {
         for(j=r;j<n-r;j++)
         printf("%d ",b[i][j]);
         printf("\n");
      }
    }
    return 0;
}

      


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值