2019杭电多校第四场 6621 K-th Closest Distance(主席树查询区间某个范围的个数)

Problem Description
传送门

思路
对distance进行二分,在区间[p-dis,d+dis]中恰有k个时,dis就是答案;
查询一个区间有多少个数在[p-dis,d+dis]内可以使用主席树或者线段树,查询一次主席树的时间复杂度为O(logn),线段树的时间复杂度为O(logn*logn);

主席树做法

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<vector>
#include<string>
#include<cstring>
#include<time.h>
#include<stdlib.h>

using namespace std;
typedef long long ll;
typedef pair<int, int>P;

const int INF = 0x3f3f3f3f;
const int NINF = 0xc0c0c0c0;
const int MAX_N = 100000+5;
const int S=(1<<18)+MAX_N*20;

struct node{
    int a,id;
};
int n,m;
node data[MAX_N+1];
int ii[MAX_N+1];
int res;
int tot;
int tree[MAX_N+1];
int kat[S],lc[S],rc[S];

bool cmp(node A,node B){
    return A.a<B.a;
}

int init(int l=1,int r=n){
    int k=++tot;
    kat[k]=0;
    lc[k]=rc[k]=0;
    if(l!=r){
        lc[k]=init(l,(l+r)/2);
        rc[k]=init((l+r)/2+1,r);
    }
    return k;
}

void build(int k,int p){
    tree[k]=++tot;
    int last=tree[k-1];
    int l=1,r=n;
    kat[tot]=kat[last]+1;
    while(l<r){
        if(p<=(l+r)/2){
            lc[tot]=tot+1;
            rc[tot]=rc[last];
            kat[++tot]=kat[lc[last]]+1;
            last=lc[last];
            r=(l+r)/2;
        }
        else{
            lc[tot]=lc[last];
            rc[tot]=tot+1;
            kat[++tot]=kat[rc[last]]+1;
            last=rc[last];
            l=(l+r)/2+1;
        }
    }
    lc[tot]=rc[tot]=0;
}

int get(int x,int y,int p,int l=1,int r=n){
    if(l==r)return kat[y]-kat[x];
    if(p>(l+r)/2)return kat[lc[y]]-kat[lc[x]]+get(rc[x],rc[y],p,(l+r)/2+1,r);
    return get(lc[x],lc[y],p,l,(l+r)/2);
}

int get2(int l,int r,int x){
    int lb=0,ub=n+1;
    while(ub-lb>1){
        int mid=(lb+ub)/2;
        if(data[mid].a<=x)lb=mid;
        else ub=mid;
    }
    if(lb==0)return 0;
    return get(tree[l-1],tree[r],lb);
}

int get3(int l,int r,int x,int y){
    return get2(l,r,y)-get2(l,r,x-1);
}

void solve(int l,int r,int p,int k){
    int lb=-1,ub=1e8;
    while(ub-lb>1){
        int mid=(lb+ub)/2;
        if(get3(l,r,p-mid,p+mid)>=k)ub=mid;
        else lb=mid;
    }
    res=ub;
    printf("%d\n",res);
}

int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            scanf("%d",&data[i].a);
            data[i].id=i;
        }
        sort(data+1,data+n+1,cmp);
        for(int i=1;i<=n;i++)ii[data[i].id]=i;
        res=0;
        tot=0;
        tree[0]=init();
        for(int i=1;i<=n;i++)build(i,ii[i]);
        int l,r,p,k;
        while(m--){
            scanf("%d%d%d%d",&l,&r,&p,&k);
            l^=res,r^=res,p^=res,k^=res;
            solve(l,r,p,k);
        }
    }
    return 0;
}

线段树做法

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<vector>
#include<string>
#include<cstring>
#include<time.h>
#include<stdlib.h>

using namespace std;
typedef long long ll;
typedef pair<int, int>P;

const int INF = 0x3f3f3f3f;
const int NINF = 0xc0c0c0c0;
const int MAX_N = 100000+5;
const int S=(1<<18);

int n,m;
int a[MAX_N];
int res;
vector<int> dat[S];
void init(int k=0,int l=0,int r=n){
    if(r-l==1){
        dat[k].resize(1);
        dat[k][0]=a[l];
        return;
    }
    int lc=k*2+1,rc=k*2+2;
    init(lc,l,(l+r)/2);
    init(rc,(l+r)/2,r);
    dat[k].resize(r-l);
    merge(dat[lc].begin(),dat[lc].end(),dat[rc].begin(),dat[rc].end(),dat[k].begin());
}

int query(int x,int y,int z,int k=0,int l=0,int r=n){
    if(x<=l&&y>=r){
        return upper_bound(dat[k].begin(),dat[k].end(),z)-dat[k].begin();
    }
    if(y<=l||x>=r)return 0;
    return query(x,y,z,k*2+1,l,(l+r)/2)+query(x,y,z,k*2+2,(l+r)/2,r);
}

int get(int x,int y,int l,int r){
    return query(l,r,y)-query(l,r,x-1);
}

void solve(int l,int r,int p,int k){
    int lb=-1,ub=1e8;
    while(ub-lb>1){
        int mid=(lb+ub)/2;
        if(get(p-mid,p+mid,l,r)>=k)ub=mid;
        else lb=mid;
    }
    res=ub;
    printf("%d\n",res);
}

int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;i++)scanf("%d",a+i);

        res=0;
        init();
        int l,r,p,k;
        while(m--){
            scanf("%d%d%d%d",&l,&r,&p,&k);
            l^=res,r^=res,p^=res,k^=res;
            solve(l-1,r,p,k);
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个基于 Python 的 K-Means++ 类的示例代码: ```python import numpy as np class KMeansPP: def __init__(self, k): self.k = k def fit(self, X): n_samples, n_features = X.shape # Initialize centroids list and add the first random centroid centroids = [X[np.random.randint(n_samples)]] # Add remaining k-1 centroids for i in range(1, self.k): # Initialize distances list distances = [] for j in range(n_samples): # Compute distance between each sample and the nearest centroid min_dist = np.inf for centroid in centroids: dist = np.linalg.norm(X[j] - centroid) min_dist = min(min_dist, dist) distances.append(min_dist) # Add a new centroid randomly based on the distance weights distances_sum = sum(distances) distances = [dist / distances_sum for dist in distances] new_centroid = X[np.random.choice(n_samples, p=distances)] centroids.append(new_centroid) self.centroids = centroids # Perform K-Means clustering clusters = [[] for _ in range(self.k)] for sample in X: distances = [np.linalg.norm(sample - centroid) for centroid in self.centroids] closest_centroid_idx = np.argmin(distances) clusters[closest_centroid_idx].append(sample) self.clusters = clusters ``` 这个类的主要功能是进行 K-Means++ 聚类,其中 `k` 是簇的数量,`X` 是形状为 `(n_samples, n_features)` 的输入数据。在 `fit` 方法中,它首先从输入数据中选择一个随机初始中心点,然后根据每个样本到最近中心点的距离选择下一个中心点,并重复此过程直到选择 `k` 个中心点。然后,它使用这些中心点对输入数据进行 K-Means 聚类,并将每个样本分配到最近的中心点的簇中。 `centroids` 和 `clusters` 属性分别存储所选的中心点和生成的簇。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值