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)); } }