zoukankan      html  css  js  c++  java
  • BOZJ 3551&BZOJ 3545 kruskal重构树

    这题是BZOJ 3545 的增强版。。。

    强制在线。。。

    对于原来普通的kruskal我们不是直接连边,而是构造新的一个点来保存这个点,然后这个点的权值就是原来的这条边的权值,然后就构造了一个新的树,对于这颗树,由于对边权排过序,所以这颗树是个堆,然后对这棵树进行dfs,求出dfs序,那么可用倍增求出第一个权值大于等于x的点,用dfs序+主席树求出k小值。

    #include <stdio.h>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    using namespace std;
    const int MAXN = 300005;
    int n,m,q,root[MAXN],f[MAXN][18];
    int L[MAXN],R[MAXN],cnt,tot,sz;//dfs序必须
    int first[MAXN],e=1,cnt_id,h[MAXN],Hash[MAXN];//邻接表
    int val[MAXN],Ans;
    
    
    template<typename _t>
    inline _t read(){
        register _t x=0,f=1;
        register char ch=getchar();
        for(;ch>'9'||ch<'0';ch=getchar())if(ch=='-')f=-f;
        for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+(ch^48);
        return x*f;
    }
    
    struct edge{
        int u,v,next,w;
        bool operator < (const edge &a)const{
            return w<a.w;
        }
    }a[MAXN<<1],ed[MAXN*5];
    
    inline void push(int u,int v){
        a[e].u=u;a[e].v=v;
        a[e].next=first[u];
        first[u]=e++;
    }
    
    struct node{
        int l,r,sum;
    }tree[5000005];
    
    #define ls(o) (tree[o].l)
    #define rs(o) (tree[o].r)
    #define sum(o) (tree[o].sum)
    
    void insert(int &o,int old,int l,int r,int val){
        o=++cnt;
        tree[o]=tree[old];
        tree[o].sum++;
        if(l==r)return;
        int m=l+r>>1;
        if(val<=m)insert(ls(o),ls(old),l,m,val);
        else insert(rs(o),rs(old),m+1,r,val);
    }
    
    inline void Hash_init(){std::sort(&Hash[1],&Hash[n+1]);sz=std::unique(&Hash[1],&Hash[n+1])-Hash-1;}
    inline int GHash(int x){return std::lower_bound(&Hash[1],&Hash[sz+1],x)-Hash;}
    
    void dfs(int u){
        L[u]=++tot;
        if(u<=n)insert(root[tot],root[tot-1],1,sz,GHash(h[u]));
        else root[tot]=root[tot-1];
        for(int i=1;i<=17;i++)f[u][i]=f[f[u][i-1]][i-1];
        for(int i=first[u];i;i=a[i].next)dfs(a[i].v);
        R[u]=tot;
    }
    
    int fa[MAXN];
    inline void init(){for(int i=1;i<=(n<<1);i++)fa[i]=i;}
    int find(int x){
        if(fa[x]==x)return x;
        fa[x]=find(fa[x]);
        return fa[x];
    }
    
    void kruskal(){
        std::sort(&ed[1],&ed[m+1]);
        for(int i=1;i<=m;i++){
            int u=find(ed[i].u),v=find(ed[i].v);
            if(u==v)continue;
            ++ cnt_id;
            fa[u]=fa[v]=cnt_id;
            f[u][0]=f[v][0]=cnt_id;
            push(cnt_id,u);push(cnt_id,v);
            val[cnt_id]=ed[i].w;
        }
        return;
    }
    
    int Query(register int old,register int now,register int l,register int r,register int k){
        if(sum(now)-sum(old)<k)return -1;
        if(l==r)return Hash[l];
        int tmp = tree[tree[now].r].sum-tree[tree[old].r].sum,m=l+r>>1;
        if(k<=tmp)return Query(tree[old].r,tree[now].r,m+1,r,k);
        else return Query(tree[old].l,tree[now].l,l,m,k-tmp);
    }
    
    int get(register int u,register int x){
        for(register int i=17;i>=0;i--)
            if(f[u][i]&&val[f[u][i]]<=x)u=f[u][i];
        return u;
    }
    
    int main(){
        n=read<int>();m=read<int>();q=read<int>();
        for(register int i=1;i<=n;i++)h[i]=read<int>(),Hash[i]=h[i];Hash_init();
        for(register int i=1;i<=m;i++)ed[i].u=read<int>(),ed[i].v=read<int>(),ed[i].w=read<int>();
        init();cnt_id=n;kruskal();
        for(register int i=1;i<=cnt_id;i++)if(!L[i])dfs(find(i));
        while(q--){
            int u=read<int>(),v=read<int>(),k=read<int>();
            if(Ans!=-1)u^=Ans,v^=Ans,k^=Ans;
            register int rt = get(u,v);
            printf("%d
    ",Ans=Query(root[L[rt]-1],root[R[rt]],1,sz,k));
        }
    }


  • 相关阅读:
    【青橙商城-管理后台开发】2. 商品服务模块搭建
    【青橙商城-管理后台开发】1.公共模块搭建
    Oracle对象-视图和索引
    Oracle的查询-分页查询
    Oracle的查询-子查询
    Oracle的查询-自连接概念和联系
    Oracle的查询-多表查询中的一些概念
    Oracle的查询-分组查询
    Oracle的查询-多行查询
    dotnet 开源库
  • 原文地址:https://www.cnblogs.com/Cooook/p/7738497.html
Copyright © 2011-2022 走看看