【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;
}
时间: 2024-10-01 07:41:34

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

BZOJ 3551 ONTAK2010 Peaks加强版 Kruskal重构树+可持久化线段树

题目大意:同3545 强制在线 3545题解传送门:http://blog.csdn.net/popoqqq/article/details/40660953 强制在线没法排序 启发式合并也就用不了了 Kruskal重构树是个挺好玩的东西 可以拿来处理一些最小生成树的边权最值问题 这里我们Kruskal连边时并不直接连边 而是新建一个节点ext 将两个点所在子树都连到ext的儿子上 比如说样例的树就建成了这样 图中红色的是原图的边权,黑色的是原图上的点 这样生成的树有一些十分优美的性质: 1.二

bzoj 3551 [ONTAK2010]Peaks加强版(kruskal,主席树,dfs序)

Description [题目描述]同3545 Input 第一行三个数N,M,Q. 第二行N个数,第i个数为h_i 接下来M行,每行3个数a b c,表示从a到b有一条困难值为c的双向路径. 接下来Q行,每行三个数v x k,表示一组询问.v=v xor lastans,x=x xor lastans,k=k xor lastans.如果lastans=-1则不变. Output 同3545 [思路] Kruskal+主席树+dfs序 一个叫kruskal重构树的方法QWQ.在kruskal合

bzoj 3551: [ONTAK2010]Peaks加强版

Description [题目描述]同3545 Input 第一行三个数N,M,Q. 第二行N个数,第i个数为h_i 接下来M行,每行3个数a b c,表示从a到b有一条困难值为c的双向路径. 接下来Q行,每行三个数v x k,表示一组询问.v=v xor lastans,x=x xor lastans,k=k xor lastans.如果lastans=-1则不变. Output 同3545 Sample Input Sample Output HINT [数据范围]同3545 Source

【BZOJ 3545】【ONTAK 2010】Peaks &amp; 【BZOJ 3551】【ONTAK 2010】Peaks加强版 Kruskal重构树

sunshine的A题我竟然调了一周!!! 把循环dfs改成一个dfs就可以,,,我也不知道为什么这样就不会RE,但它却是A了,,, 这周我一直在调这个题,总结一下智障错误: 1.倍增的范围设成了n而不是n*2-1,,, 2.重构树的顶点是n*2-1,而我一开始设成了n,,, 3.define里的for3和for4的i--打成i++,,,,,,,,,,,, 4.dfs爆栈了,找CA爷问的编译命令里手动扩栈,真是愚蠢的问题,,,, 比赛时绝不会有太多时间,在这么犯逗就得滚粗了QAQ 3545: #

[IOI2018]werewolf狼人——kruskal重构树+可持久化线段树

题目链接: IOI2018werewolf 题目中编号都是从0开始,太不舒服了,我们按编号从1开始讲QAQ. 题目大意就是询问每次从一个点开始走只能走编号在[l,n]中的点,在任意点变成狼,之后只能走[0,r]中的点,是否能到达另一个点. 后一部分其实就是找有哪些点只走[0,r]中的点能到达终点,那么反过来看,就是终点只走[0,r]中的点能到达哪些点. 那么只要起点能到达的点和终点能到达的点中有交集就有解. 因为起点只能走一些编号较大的点,那么我们求出原图的最大生成树,建出kruskal重构树,

bzoj 3545&amp;&amp;3551: [ONTAK2010]Peaks &amp;&amp;加强版 平衡树&amp;&amp;并查集合并树&amp;&amp;主席树

3545: [ONTAK2010]Peaks Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 635  Solved: 177[Submit][Status] Description 在Bytemountains有N座山峰,每座山峰有他的高度h_i.有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问询问从点v开始只经过困难值小于等于x的路径所能到达的山峰中第k高的山峰,如果无解输出-1. I

BZOJ 2588: Spoj 10628. Count on a tree 树上跑主席树

2588: Spoj 10628. Count on a tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=2588 Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文. Inp

【BZOJ 3732】 Network Kruskal重构树+倍增LCA

Kruskal重构树裸题, Sunshine互测的A题就是Kruskal重构树,我通过互测了解到了这个神奇的东西... 理解起来应该没什么难度吧,但是我的Peaks连WA,,, 省选估计要滚粗了TwT #include<cstdio> #include<cstring> #include<algorithm> #define for1(i,a,n) for(int i=(a);i<=(n);i++) #define for2(i,a,n) for(int i=(a

BZOJ 3732 Network Kruskal重构树

题目大意:给定一个n个点m条边的无向连通图,k次询问两点之间所有路径中最长边的最小值 Kruskal+倍增LCA做法见http://blog.csdn.net/popoqqq/article/details/39755703 LCT做法见http://blog.csdn.net/popoqqq/article/details/39929277 Kruskal重构树真是强大--一不小心手滑就RANK1啥的-- 每加入一条边时,我们并不链接这条边的两端点,而是把这条边两端点所在并查集的根连接起来,而