您的位置:首页 > 其它

HDU 5021 Revenge of kNN II 线段树

2014-09-19 21:23 375 查看
【题目大意】

有n个点,每个点都两个属性:坐标和价值。有m次询问,对一次询问,q,k,你首先要找到点q最近的k个点(不包括点q,如果边界有两个点都可以选,选择坐标小的)。然后求这k个点的平均价值,使 ans += 平均值,并把点q的价值改为这个平均值。最后输出ans。

【思路】

这个问题的关键是找到要最近的k个点,具体是哪k个。如果搞定了这个问题,剩下的就是线段树的基础操作了。如果按坐标排序后,可以使用二分去找k个点所属区间。但是这题直接二分是有点麻烦的。我采用的是二分距离,找到最近的k个点中,最远的那个点距离;之后再特判一下边界就行了,这种做法比较好写。

//#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
#include<cctype>
#include<string>
#include<algorithm>
#include<iostream>
#include<ctime>
#include<map>
#include<set>
using namespace std;
#define MP(x,y) make_pair((x),(y))
#define PB(x) push_back(x)
typedef __int64 LL;
//typedef unsigned __int64 ULL;
/* ****************** */
const int INF = 1000111222;
const double INFF = 1e100;
const double eps = 1e-8;
const int mod = 1000000007;
const int NN = 100009;
const int MM = 400010;
/* ****************** */

struct TR
{
int l,r;
double sum;
int mid()
{
return (l+r)>>1;
}
}tr[NN*4];

struct node
{
int x,id;
double v;
bool operator<(const node &tt)const
{
return x < tt.x;
}
}a[NN];
int tf[NN];
int id[NN];
int idd[NN];

void push_up(int R)
{
tr[R].sum = tr[R<<1].sum + tr[R<<1|1].sum;
}
void build(int l,int r,int R)
{
tr[R].l = l;
tr[R].r = r;
if(l==r)
{
tr[R].sum = a[tr[R].l].v;
return ;
}
int mid = tr[R].mid();
build(l,mid,R<<1);
build(mid+1,r,R<<1|1);
push_up(R);
}
double query(int l,int r,int R)
{
if(l<=tr[R].l && tr[R].r<=r)
return tr[R].sum;
double ans = 0.0;
int mid = tr[R].mid();
if(l<=mid)
ans += query(l,r,R<<1);
if(r>=mid+1)
ans += query(l,r,R<<1|1);
return ans;
}
void update(int x,int R,double col)
{
if(tr[R].l == tr[R].r)
{
tr[R].sum = col;
return;
}
int mid = tr[R].mid();
if(x<=mid)
update(x,R<<1,col);
else
update(x,R<<1|1,col);
push_up(R);
}

int find(int n,int l,int r)
{
int ans = upper_bound(tf+1,tf+1+n,r) - lower_bound(tf+1,tf+1+n,l);
return ans;
}

void solve(int n,int m)
{
int x,k,l,r,st,mid,t;
double sum, ans = 0.0;
while(m--)
{
scanf("%d%d",&x,&k);
x = id[x];

l = 0;
r = 1000000000;
while (l + 1 < r)
{
mid = (l + r) >> 1;
t = find(n,a[x].x-mid,a[x].x+mid);
if(t >= k+1)
r = mid;
else
l = mid;
}

// printf("r==%d\n",r);

st = lower_bound(tf+1,tf+1+n,a[x].x-r) - tf;

if(st+k+1 <= n && tf[st+k+1]-tf[x] == tf[x]-tf[st] && idd[st+k+1] < idd[st])
st++;

// printf("[] == %d %d\nx==%d\n",st,st+k,x);

sum = query(st,st+k,1);

// cout<<"sum=="<<sum<<endl;

sum -= a[x].v;
sum /= (k+0.0);

// cout<<"update=="<<sum<<endl;

ans += sum;

update(x,1,sum);
a[x].v = sum;
}

// cout<<"ans=="<<tr[1].sum<<endl;

printf("%.3lf\n",ans);
}

int main()
{
int cas,i,t,n,m;
scanf("%d",&cas);
while(cas--)
{
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
{
scanf("%d%d",&a[i].x,&t);
a[i].v = t;
a[i].id = i;
}

sort(a+1,a+1+n);

for(i=1;i<=n;i++)
{
tf[i] = a[i].x;
id[a[i].id] = i;
idd[i] = a[i].id;
}

// for(i=1;i<=n;i++)
// {
// printf("%d %d ???\n",a[i].x,a[i].id);
// // printf("-> %d\n",id[i]);
// }

build(1,n,1);

solve(n,m);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: