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\n",Ans=Query(root[L[rt]-1],root[R[rt]],1,sz,k));
    }
}


posted @ 2017-08-02 21:26  cooook  阅读(138)  评论(0编辑  收藏  举报