zoukankan      html  css  js  c++  java
  • 洛谷P4197 Peaks&&克鲁斯卡尔重构树学习笔记(克鲁斯卡尔重构树+主席树)

    传送门

    据说离线做法是主席树上树+启发式合并(然而我并不会)

    据说bzoj上有强制在线版本只能用克鲁斯卡尔重构树,那就好好讲一下好了

    这里先感谢LadyLex大佬的博客->这里

    克鲁斯卡尔重构树可以用来解决一类诸如“查询从某个点出发经过边权不超过val的边所能到达的节点”的问题

    首先不难发现,上面这个问题肯定是在最小生成树上走最优,其他边都可以不用去管

    那么我们就在建最小生成树的时候搞事情

    克鲁斯卡尔重构树的思想就是在建最小生成树的时候不是直接连边,而是新建一个节点,并把这个节点的值设为边权,然后令两个连通块的代表点分别作为它的左右儿子。然后令这个新节点成为整个连通块的代表点

    说了那么多跟没说一样……举个栗子好了

    假设现在有四个节点,要求他们的克鲁斯卡尔重构树

    我们按最小生成树的方法找,先把边按权值从小到大排序。

    然后设第一条边权值为4,连接1和2这两个连通块

    然后新建一个节点5,点权设为4,并把1和2作为他的左右儿子

    第二条边权值为6,连接3和4这两个连通块

    然后新建一个节点6,点权设为6,并把3和4作为他的左右儿子

    第三条边权值为7,连接1和2,那么我们就是要把4和6的连通块相连了(这两个是连通块的代表点)

    然后新建一个节点7,点权设为7,并把5和6作为他的左右儿子

    然后这一棵克鲁斯卡尔重构树就建好了٩(๑>◡<๑)۶

    不难发现它有一个性质,每一个儿子节点的权值都小于等于自己的权值(因为我们是按最小生成树的顺序建的)

    那么要查“查询从某个点出发经过边权不超过val的边所能到达的节点”

    因为我们一个原来图上的点肯定是叶子结点,所以我们只要从叶子结点开始往上找,直到找到最后一个点权小于等于$val$的点

    那么这个点为根的子树里的所有点都能到达

    怎么找呢?倍增就行了

    放到这一题里,因为要查询第$k$大,所以还得套个主席树上树

    然而就差不多了

     1 //minamoto
     2 #include<iostream>
     3 #include<cstdio>
     4 #include<cstring>
     5 #include<algorithm>
     6 using namespace std;
     7 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
     8 char buf[1<<21],*p1=buf,*p2=buf;
     9 inline int read(){
    10     #define num ch-'0'
    11     char ch;bool flag=0;int res;
    12     while(!isdigit(ch=getc()))
    13     (ch=='-')&&(flag=true);
    14     for(res=num;isdigit(ch=getc());res=res*10+num);
    15     (flag)&&(res=-res);
    16     #undef num
    17     return res;
    18 }
    19 char sr[1<<21],z[20];int C=-1,Z;
    20 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
    21 inline void print(int x){
    22     if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;
    23     while(z[++Z]=x%10+48,x/=10);
    24     while(sr[++C]=z[Z],--Z);sr[++C]='
    ';
    25 }
    26 const int N=2e5+5,M=N*16,K=5e5+5;
    27 struct node{
    28     int from,to,cost;
    29     node(){}
    30     node(int from,int to,int cost):from(from),to(to),cost(cost){}
    31     inline bool operator <(const node &b)const
    32     {return cost<b.cost;}
    33 }E[K];
    34 int head[N],Next[N],ver[N],sum[M],L[M],R[M],bin[25],cnt,tot;
    35 int fa[N],f[N][20],ls[N],rs[N],rt[N],val[N],num;
    36 int h[N],limit,b[N],n,q,m,ans=0,dfn;
    37 inline void mission(int u){
    38     for(int i=1;bin[i]<=n;++i)
    39     f[u][i]=f[f[u][i-1]][i-1];
    40 }
    41 inline void add(int u,int v){
    42     ver[++tot]=v,Next[tot]=head[u],head[u]=tot;
    43 }
    44 int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
    45 void update(int last,int &now,int l,int r,int x){
    46     sum[now=++cnt]=sum[last]+1;
    47     if(l==r) return;
    48     int mid=(l+r)>>1;
    49     if(x<=mid) R[now]=R[last],update(L[last],L[now],l,mid,x);
    50     else L[now]=L[last],update(R[last],R[now],mid+1,r,x);
    51 }
    52 int query(int a,int x,int k){
    53     int l=1,r=limit;
    54     for(int j=18;~j;--j)
    55     if(f[a][j]&&val[f[a][j]]<=x) a=f[a][j];
    56     int v=rt[rs[a]],u=rt[ls[a]-1];
    57     if(sum[v]-sum[u]<k) return -1;
    58     while(l<r){
    59         int tmp=sum[R[v]]-sum[R[u]],mid=(l+r)>>1;
    60         if(tmp>=k) v=R[v],u=R[u],l=mid+1;
    61         else v=L[v],u=L[u],r=mid,k-=tmp;
    62     }
    63     return b[r];
    64 }
    65 void dfs(int u){
    66     mission(u),ls[u]=++num;
    67     if(u<=n) update(rt[num-1],rt[num],1,limit,h[u]);
    68     else rt[num]=rt[num-1];
    69     for(int i=head[u];i;i=Next[i]) dfs(ver[i]);
    70     rs[u]=num;
    71 }
    72 int main(){
    73 //    freopen("testdata.in","r",stdin);
    74     n=read(),m=read(),q=read();
    75     bin[0]=1;for(int i=1;i<=22;++i) bin[i]=bin[i-1]<<1;
    76     for(int i=1;i<=2*n;++i) fa[i]=i;
    77     for(int i=1;i<=n;++i) b[i]=h[i]=read();
    78     for(int i=1,u,v,e;i<=m;++i)
    79     u=read(),v=read(),e=read(),E[i]=node(u,v,e);
    80     sort(b+1,b+1+n),limit=unique(b+1,b+1+n)-b-1;
    81     for(int i=1;i<=n;++i) h[i]=lower_bound(b+1,b+1+limit,h[i])-b;
    82     sort(E+1,E+1+m);dfn=n;
    83     for(int i=1;i<=m;++i){
    84         int u=find(E[i].from),v=find(E[i].to);
    85         if(u!=v){
    86             val[++dfn]=E[i].cost,fa[u]=fa[v]=dfn;
    87             add(dfn,u),add(dfn,v),f[u][0]=f[v][0]=dfn;
    88             if(dfn-n==n-1) break;
    89         }
    90     }
    91     for(int i=1;i<=dfn;++i) if(!ls[i]) dfs(find(i));
    92     while(q--){
    93         int v=read(),x=read(),k=read();
    94         print(query(v,x,k));
    95     }
    96     Ot();
    97     return 0;
    98 }
  • 相关阅读:
    删除commit(暂存区)中的文件(git)
    bower安装使用以及git安装
    compass模块----Utilities----Sprites精灵图合图
    compass模块----Utilities
    compass模块----Helpers
    compass模块
    compass安装
    Sass@规则
    Sass函数--颜色函数--Opacity函数
    Sass函数--颜色函数--HSL函数
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/9680934.html
Copyright © 2011-2022 走看看