hdu5021 树状数组+二分

这 题 说 的 是 给 了 一 个 K—NN    每次查询离loc 最近的k个数 然后将这k个数的权值加起来除以k 赋值给 loc 这个位置上的 权值

 我说说 我的做法 假如 查询的是loc 这个位置 k 个 ,然后 就让 L=1 R= loc 对于每个 二分 的 mid  假设mid 是这k个数最左的那个的下标 然后对于每个最左的下标 我们可以知道 这k 个数的最右点在哪里 然后就判断 这个区间是否要左移 或者右移 左移 R=mid 右移 L=mid+1 然后不断的去调整 找到最后的L和R后用树状数组去维护就好了
#include <iostream>
#include <cstdio>
#include <string.h>
#include <algorithm>
using namespace std;
typedef int ll;
const int max_n =100005;
const int INF =(1e9)*2;
struct point{
   ll loc,num;
   double val;
   bool operator <(const point A)const{
       return loc<A.loc;
   }
}P[max_n];
int n,m;
double C[max_n];
int lowbit(int x){
  return x&(-x);
}
void add(int x, double v){
     while(x<=n){
         C[x]+=v;
         x+=lowbit(x);
     }
}
double sum(int x){
    double ans=0;
    while(x>0){
         ans+=C[x];
         x-=lowbit(x);
    }
    return ans;
}
int id[max_n];
ll dist[max_n];
void binser(int &L, int &R,int loc, int num){
     L=max(1,loc-num);
     R= loc;
     ll S1,nu,S2;
     while(L<R){
         int mid =(R+L)/2;
         S1=dist[loc]-dist[mid];
         nu = num-(loc-mid)+loc;
         if(nu<loc){
            L=mid+1; continue;
         }
         if(nu>n){
            R=mid;continue;
         }
         S2=dist[nu]-dist[loc];
         if(S1>S2){
            L=mid+1;
         }else {
            R=mid;
         }
     }
     L = min(L,loc);
     R = num - ( loc - L ) + loc ;
     L = min( L + 1 , loc );
     R = max( loc , R - 1 );
     int ge = R-loc + loc - L;
     while(ge!=num){
       if(R>=n||(L>1&&dist[loc]-dist[L-1]<dist[R+1]-dist[loc])
       ||(L>1&&dist[loc]-dist[L-1]==dist[R+1]-dist[loc]&&P[L-1].num<P[R+1].num))
           L--;
        else R++;
        ge++;
     }
}
int main()
{
    int cas;
    scanf("%d",&cas);
    while(cas--){
            for(int i=0; i<=n; i++)
              C[i]=0.0;
        scanf("%d%d",&n,&m);
        for(int i =1; i<=n; i++){
            ll loc;
            double val;
            scanf("%d%lf",&loc,&val);
            P[i].loc=loc;
            P[i].num=i;
            P[i].val=val;
        }
        sort( P + 1 , P + n + 1 );
        for(int i=1; i <= n ;++i){
                id[ P[i].num ] = i;
                dist[ i ] = P[ i ].loc;
                add( i , P[i].val );
         }
         dist[n+1]=INF;
         double ans=0;
         double S;
       while(m--){
            int loc, k;
            scanf("%d%d",&loc,&k);
            if(loc<1||k<1||k>=n)while(true);
            loc=id[loc];
            int L,R;
            binser(L,R,loc,k);
            add(loc,-P[loc].val);
            S =sum(R)-sum(L-1);
            S=S/k;
            ans=ans+S;
            add(loc,S);
            P[loc].val=S;
        }
        printf("%.3f\n",ans);
    }
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/Opaser/p/3986518.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值