首页 > 代码库 > 【BZOJ 3551】[ONTAK2010] Peaks加强版 Kruskal重构树+树上倍增+主席树

【BZOJ 3551】[ONTAK2010] Peaks加强版 Kruskal重构树+树上倍增+主席树

这题真刺激......

I.关于Kruskal重构树,我只能开门了,不过补充一下那玩意还是一棵满二叉树。(看一下内容之前请先进门坐一坐)

II.原来只是用树上倍增求Lca,但其实树上倍增是一种方法,Lca只是他的一种应用,他可以搞各种树上问题,树上倍增一般都会用到f数组。

|||.我们跑出来dfs序就能在他的上面进行主席树了。

IV.别忘了离散。

V.他可能不连通,我一开始想到了,但是我觉得出题人可能会是好(S)人(B),但是......

#include <cstdio>
#include <algorithm>
#define N 150000
#define M 550000
using namespace std;
inline int read()
{
  register int sum=0;
  register char ch=getchar();
  while(ch<0||ch>9)ch=getchar();
  while(ch>=0&&ch<=9){
    sum=(sum<<1)+(sum<<3)+ch-0;
    ch=getchar();
  }
  return sum;
}
int n,m,Q;
struct E{
  int x,y,z;
}e[M+10];
int comp(const E a,const E b){
  return a.z<b.z;
}
struct Via{
  int to,next;
}c[M];
int head[M>>1],t;
int h[N+10],dfs[M>>1],l[M>>1],r[M>>1],Time;
int len,Hash[N+10];
struct Seg_Tree{
  Seg_Tree *ch[2];
  int l,r,size;
}*root[M>>1],*null;
int d[M>>1][20],f[M>>1][20],P[N+10],fa[M>>1];
int Comp(const int x,const int y){
  return h[x]>h[y];
}
//*********************Define***********************
inline Seg_Tree *New(int l,int r){
  register Seg_Tree *p=new Seg_Tree;
  p->l=l,p->r=r,p->size=0,p->ch[0]=p->ch[1]=null;
  return p;
}
void ins(Seg_Tree *&p,Seg_Tree *last,int z,int y,int key)
{
  p=New(z,y),p->size=last->size,p->size++;
  if(p->l==p->r) return; 
  p->ch[0]=last->ch[0],p->ch[1]=last->ch[1];
  if(key<=((z+y)>>1))ins(p->ch[0],last->ch[0],z,((z+y)>>1),key);
  else ins(p->ch[1],last->ch[1],((z+y)>>1)+1,y,key);
}
int query(Seg_Tree *a,Seg_Tree *b,int k,int z,int y)
{
  if(z==y)return z;
  if(a->ch[0]->size-b->ch[0]->size>=k)return query(a->ch[0],b->ch[0],k,z,(z+y)>>1);
  else return query(a->ch[1],b->ch[1],k-(a->ch[0]->size-b->ch[0]->size),((z+y)>>1)+1,y);
}
//*********************Seg_Tree*********************
inline void add(int x,int y){
  c[++t].to=y;
  c[t].next=head[x];
  head[x]=t;
}
inline int find(int x){
  return x==fa[x]?x:(fa[x]=find(fa[x]));
}
inline int Max(int x,int y){
  return x>y?x:y;
}
void Dfs(int x){
  l[x]=++Time,dfs[Time]=x;
  for(register int i=1;i<20;i++)f[x][i]=f[f[x][i-1]][i-1];
  for(register int i=1;i<20;i++)d[x][i]=Max(d[x][i-1],d[f[x][i-1]][i-1]);
  for(register int i=head[x];i;i=c[i].next)Dfs(c[i].to);
  r[x]=Time;
}
inline void Kruskal(){
  sort(e+1,e+m+1,comp);
  for(register int i=1;i<=n+n;i++)fa[i]=i;
  for(register int i=1,had=0;had<n-1&&i<=m;i++)
  if(find(e[i].x)!=find(e[i].y)){
    register int X=find(e[i].x),Y=find(e[i].y);
    had++,add(had+n,X),add(had+n,Y),d[X][0]=d[Y][0]=e[i].z;
    f[X][0]=f[Y][0]=fa[X]=fa[Y]=had+n;
  }
  for(register int i=1;i<=n;i++)
    if(!l[find(i)])Dfs(find(i));
}
inline int get_root(int x,int lim)
{
  for(register int i=19;i>=0;i--)
    if(f[x][i]&&d[x][i]<=lim)
      x=f[x][i];
  return x;
}
//********************Kruskal************************
inline void HASH(){
  sort(P+1,P+n+1,Comp);
  for(register int i=1;i<=n;i++)
    if(i==1||h[P[i]]!=h[P[i-1]])
      Hash[++len]=h[P[i]],h[P[i]]=len;
    else h[P[i]]=len;
}
//********************Hash***************************
inline void Init(){
  n=read(),m=read(),Q=read(),null=New(0,0),null->ch[0]=null->ch[1]=null,root[0]=null;
  for(register int i=1;i<=n;i++)h[i]=read(),P[i]=i;HASH();
  for(register int i=1;i<=m;i++)e[i].x=read(),e[i].y=read(),e[i].z=read();Kruskal();
  for(register int i=1;i<=Time;i++)
    if(dfs[i]<=n)  root[i]=null,ins(root[i],root[i-1],1,len,h[dfs[i]]);
    else root[i]=root[i-1];
}
inline void Work(){
    register int v,x,k,ans=0;
    while(Q--){
    v=read(),x=read(),k=read();
    register int Root=get_root(v,x);
    if(root[r[Root]]->size-root[l[Root]-1]->size<k){
      puts("-1"),ans=0;continue;
    }
    printf("%d\n",(ans=Hash[query(root[r[Root]],root[l[Root]-1],k,1,len)]));
  }
}
int main(){
  Init();
  Work();
  return 0;
}

 

【BZOJ 3551】[ONTAK2010] Peaks加强版 Kruskal重构树+树上倍增+主席树