zoukankan      html  css  js  c++  java
  • bzoj 3551 kruskal重构树dfs序上的主席树

    强制在线

    kruskal重构树,每两点间的最大边权即为其lca的点权。

    倍增找,dfs序对应区间搞主席树

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    #include<algorithm>
    #define N 100005
    #define M 500005
    using namespace std;
     
    int l[2*N],r[2*N],cnt,num_cnt,val[2*N],num[2*N],ans;
    int sum[25*N],lon[25*N],ron[25*N];
    int be[2*N],fa[2*N][21],dis[2*N][21],n,m,q,sz,oo,root[2*N];
    int e=1,head[2*N];
    bool vis[2*N];
    struct edge{
        int u,v,w,next;
    }ed[M],a[M];
    bool cmp1(edge a,edge b){return a.w<b.w;}
     
    void add(int u,int v,int w){
        ed[e].u=u; ed[e].v=v; ed[e].w=w;
        ed[e].next=head[u]; head[u]=e++;
    }
    int find(int x){
        if(x==be[x])return x;
        be[x]=find(be[x]);
        return be[x];
    }
    void Kruskal(){
        sort(a+1,a+m+1,cmp1);
        for(int i=1;i<=m;++i){
            int u=a[i].u,v=a[i].v;
            u=find(u); v=find(v);
            if(u!=v){
                be[u]=be[v]=++n;
                fa[u][0]=fa[v][0]=n;
                dis[u][0]=dis[v][0]=a[i].w;
                add(n,u,a[i].w); add(n,v,a[i].w);
            }
        }
    }
    void insert(int p,int &rt,int l,int r,int x){
        rt=++sz;
        sum[rt]=sum[p]+1;
        if(l==r) return;
        lon[rt]=lon[p]; ron[rt]=ron[p];
        int mid=(l+r)>>1;
        if(x<=mid) insert(lon[p],lon[rt],l,mid,x);
        else insert(ron[p],ron[rt],mid+1,r,x);
    }
    void dfs(int x){
    	for(int i=1;i<=20;i++){
            fa[x][i]=fa[fa[x][i-1]][i-1];
            dis[x][i]=max(dis[x][i-1],dis[fa[x][i-1]][i-1]);
        }
        l[x]=++cnt; 
        if(x<=oo) insert(root[cnt-1],root[cnt],1,num_cnt,val[x]);
        else root[cnt]=root[cnt-1];
        for(int i=head[x];i;i=ed[i].next)
               dfs(ed[i].v);
        r[x]=cnt;
    }
    int query(int L,int R,int k){
        L=root[L]; R=root[R];
        if(k>sum[R]-sum[L]) return -1;
        int x=1,y=num_cnt;
        while(x<y){
            int mid=(x+y)>>1;
            int tmp=sum[ron[R]]-sum[ron[L]];
            if(tmp>=k){x=mid+1;L=ron[L];R=ron[R];}
            else{k-=tmp;y=mid;L=lon[L];R=lon[R];}
        }
        return num[x];
    }
    void print(int x,int l,int r){
        if(!x) return;
        printf("x==%d  l==%d  r==%d  sum==%d
    ",x,l,r,sum[x]);
        int mid=(l+r)>>1;
        print(lon[x],l,mid);
        print(ron[x],mid+1,r);
    }
    int main()
    {
    	//freopen("3545.in","r",stdin);
    	//freopen("3545.out","w",stdout);
        int u,v,w,x,k;
        scanf("%d%d%d",&n,&m,&q); oo=n;
        for(int i=1;i<=n;i++){
            scanf("%d",&val[i]);
            num[i]=val[i];
        }
        sort(num+1,num+n+1);
        num_cnt=unique(num+1,num+n+1)-num-1;
        for(int i=1;i<=n;i++)
            val[i]=lower_bound(num+1,num+num_cnt+1,val[i])-num;
        for(int i=1;i<=m;i++)
            scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w);
        for(int i=1;i<=2*n;++i)be[i]=i;
        Kruskal();
        memset(vis,0,sizeof vis);
        for(int i=n;i>=1;--i)if(!l[i])dfs(i);
        while(q--){
            scanf("%d%d%d",&v,&x,&k);
            if(ans!=-1){v^=ans;x^=ans;k^=ans;}
            for(int i=20;~i;i--)
                if(dis[v][i]<=x&&fa[v][i])
                    v=fa[v][i];
            ans=query(l[v]-1,r[v],k);
            printf("%d
    ",ans);
        }
        return 0;
    }


  • 相关阅读:
    图论算法(三) 最短路SPFA算法
    图论算法(二)最短路算法:Floyd算法!
    图论算法(一)存图与STL第六弹——vector容器
    C++指针变量的基本写法
    杂记——深度优先搜索(dfs)与出题感想
    分治算法(二分查找)、STL函数库的应用第五弹——二分函数
    网站开发小技巧总结
    网站开发动态效果插件
    jquery获得ul下li的个数
    jquery的循环函数和点击事件绑定
  • 原文地址:https://www.cnblogs.com/Ren-Ivan/p/7746720.html
Copyright © 2011-2022 走看看