【清华集训2017模拟11.29】K小数查询

本文介绍了一种使用分块和二分查找技术解决区间最小值及第k小值问题的方法。适用于处理大规模数据集,通过预处理提高查询效率。

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

Description

维护一个数据结构,资瓷区间取min和区间求k小值。
n<=8*1e4

Solution

和由乃OI那题很像,直接分块,块内归并重构,二分答案块内二分查询。
只不过比较良心的是JZOJ上不卡常,但是我块大小开nlognT了,开n过了。。。

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define rep(i,a) for(int i=lst[a];i;i=nxt[i])
using namespace std;

int read() {
    char ch;
    for(ch=getchar();ch<'0'||ch>'9';ch=getchar());
    int x=ch-'0';
    for(ch=getchar();ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
    return x;
}

void write(int x) {
    if (!x) {puts("0");return;}
    if (x<0) {putchar('-');x=-x;}
    char ch[20];int tot=0;
    for(;x;x/=10) ch[++tot]=x%10+'0';
    fd(i,tot,1) putchar(ch[i]);
    puts("");
}

inline int min(int x,int y) {return x<y?x:y;}

const int N=8*1e4+5,M=500;

struct P{int v,w;}a[N],b[N],c[N];
bool cmp(P x,P y) {return x.v<y.v;}

int bl[N],L[N],R[N],lazy[N],Sz,n,m;

int find(int w) {fo(i,1,Sz) if (L[i]<=w&&w<=R[i]) return i;}

int p[N],q[N];
bool bz[N];

void rebuild(int v,int l,int r,int k) {
    fo(i,L[v],R[v]) bz[i]=0;
    fo(i,l,r) a[i].v=min(a[i].v,k),bz[a[i].w]=1;

    q[0]=p[0]=0;
    fo(i,L[v],R[v]) 
        if (bz[i]) q[++q[0]]=i;
        else p[++p[0]]=i;

    int i=1,j=1,cnt=0;
    while (i<=q[0]&&j<=p[0]) {
        if (min(b[q[i]].v,k)<b[p[j]].v) {c[++cnt]=b[q[i++]];c[cnt].v=min(c[cnt].v,k);}
        else c[++cnt]=b[p[j++]];
    }
    while (i<=q[0]) {c[++cnt]=b[q[i++]];c[cnt].v=min(c[cnt].v,k);}
    while (j<=p[0]) c[++cnt]=b[p[j++]];

    fo(i,1,cnt) b[L[v]+i-1]=c[i];
    fo(i,L[v],R[v]) a[b[i].w].w=i;
}

int len,opt,x,k,z,l,r,u,v;

int solve(int u,int l,int r,int v) {
    int cnt=0;
    fo(i,l,r) if (min(a[i].v,lazy[u])<=v) cnt++;
    return cnt;
}

int query(int u,int v) {
    int l=L[u],r=R[u]+1;
    while (l<r) {
        int mid=l+r>>1;
        if (min(b[mid].v,lazy[u])<=v) l=mid+1;
        else r=mid;
    }
    return l-L[u];
}

int check(int mid) {
    int res=0;
    if (u==v) return solve(u,l,r,mid);
    res=solve(u,l,R[u],mid)+solve(v,L[v],r,mid);
    fo(i,u+1,v-1) res+=query(i,mid);
    return res;
}

int main() {
    n=read();m=read();
    fo(i,1,n) a[i].v=read(),a[i].w=i;

    fo(i,1,n) bl[i]=(i-1)/M+1;Sz=bl[n];
    fo(i,1,Sz) L[i]=R[i-1]+1,R[i]=min(L[i]+M-1,n);
    fo(i,1,Sz) {
        lazy[i]=n+1;
        fo(j,L[i],R[i]) b[j]=a[j];
        sort(b+L[i],b+R[i]+1,cmp);
        fo(j,L[i],R[i]) a[b[j].w].w=j;
    }

    for(;m;m--) {
        opt=read();l=read();r=read();k=read();
        if (!k) {write(1);continue;}
        u=find(l);v=find(r);
        if (opt==2) {
            int le=0,ri=n+1;
            while (le<ri) {
                int mid=le+ri>>1;
                if (check(mid)>=k) ri=mid;
                else le=mid+1;
            }
            write(le);
        } else {
            if (u==v) {rebuild(u,l,r,k);continue;}
            fo(i,u+1,v-1) lazy[i]=min(lazy[i],k);
            rebuild(u,l,R[u],k);rebuild(v,L[v],r,k);
        }
    }

    return 0;
}
手肘法(Elbow Method)是一种用于确定K-means聚类算法中的最佳簇数(K值)的方法。以下是一个示例Python代码,展示如何使用手肘法来确定最佳的K值: 首先,我们需要将表格数据转换为一个适合进行聚类分析的数据格式。假设我们已经将数据读取到一个Pandas DataFrame中。 ```python import pandas as pd from sklearn.cluster import KMeans import matplotlib.pyplot as0 plt # 示例数据 data = { 'city': ['郑州', '开封', '洛阳', '平顶山', '安阳', '鹤壁', '新乡', '焦作', '濮阳', '许昌', '漯河', '三门峡', '南阳', '商丘', '信阳', '周口', '驻马店', '济源'], 'legal_entities_num': [1437, 650, 764, 352, 467, 174, 456, 530, 500, 658, 368, 552, 750, 920, 436, 555, 578, 105], 'employed_individuals_num': [22.01, 11.06, 16.87, 20.57, 10.75, 4, 11.82, 11.29, 7.56, 8, 5.54, 5.55, 20.44, 15.81, 30.71, 4.85, 13.39, 2.42], 'highway_length': [12702, 8844, 18342, 13468, 11817, 4464, 13106, 7383, 6465, 9288, 5250, 9520, 38004, 23050, 24755, 21845, 19272, 2284], 'freight_transportation_volume': [19709, 2588, 16570, 9289, 10294, 5018, 16050, 15295, 3172, 5997, 5322, 4424, 15696, 15083, 6610, 15178, 9479, 3906], 'cargo_turnover_expess_revenue': [332.36, 98.54, 401.92, 209.27, 416.09, 105.31, 311.43, 431.35, 148.79, 190.71, 108.71, 140.78, 581.94, 421.47, 54.4, 619.24, 149.27, 100.78], 'packages_num': [57.67, 2.41, 29.75, 2.04, 11.86, 0.91, 22.25, 8.22, 10.15, 7.47, 4.45, 5.2, 40.92, 14.82, 8.74, 13.5, 11.34, 2.5], 'package_business_volume': [42375, 1915, 5761, 1177, 2460, 711, 3705, 3307, 1248, 2348, 2222, 843, 3920, 4865, 2257, 2332, 1981, 450], 'postal_route_length': [7942, 1651, 4392, 1802, 1721, 456, 3013, 1189, 1264, 1516, 977, 1338, 5356, 3347, 5902, 3300, 3277, 420], 'postal_business_volume': [39.99, 3.59, 7.32, 3.2, 5, 1.1, 6.49, 3.67, 2.82, 3.79, 2.57, 1.96, 8.63, 7.15, 5.26, 6.8, 6.53, 0.66], 'cargo_vehicles_num': [156902, 43148, 91485, 51677, 42115, 16675, 67624, 31029, 55093, 53622, 25914, 26470, 97209, 86693, 58170, 116577, 57440, 9830], 'phone_users_num': [1281.59, 337.66, 575.81, 377.39, 451.87, 131.64, 529.3, 300.91, 293.46, 335.82, 188.02, 189.79, 655.87, 577.64, 413.23, 538.82, 464.77, 69.33] } # 创建DataFrame df = pd.DataFrame(data) # 选择需要进行聚类的特征列 features = df.drop(columns=['city']) # 初始化SSE列表 sse = [] # 尝试不同的K值 for k in range(1, 11): kmeans = KMeans(n_clusters=k, random_state=42) kmeans.fit(features) sse.append(kmeans.inertia_) # 绘制SSE曲线 plt.figure(figsize=(10, 6)) plt.plot(range(1, 11), sse, marker='o') plt.title('Elbow Method For Optimal k') plt.xlabel('Number of clusters') plt.ylabel('SSE') plt.show() ``` ### 解释 1. **数据准备**:我们将表格数据存储在一个字典中,并将其转换为Pandas DataFrame。 2. **特征选择**:我们选择除了城市名称之外的所有列作为特征列。 3. **计算SSE**:我们尝试从1到10的不同K值,计算每个K值对应的SSE(Sum of Squared Errors)。 4. **绘制SSE曲线**:通过绘制SSE随K值变化的曲线,我们可以观察到“肘部”点,即SSE下降速度明显减缓的点。这个点通常被认为是最佳的K值。 运行上述代码后,你会看到一张SSE随K值变化的图表。通过观察图表中的“肘部”,可以确定最佳的K值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值