这 题 说 的 是 给 了 一 个 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; }