• [NOI2018]归程


    神奇的kruskal重构树(考场不会可以现场发明)。。。

    首先跑一遍dj,则对于每次询问,答案就是v能到的所有点中dis最小的点的dis

    考虑按海拔高度,从大到小加边直到图联通,我们需要维护每个点所在的连通块,以及每个连通块中dis最小的点

    离线。。。并查集?

    强制在线。。。可持久化并查集?

    有没有更优秀的做法?我们可以用kruskal重构树。

    对于加入的一条边(u,v),我们找到u和v所在树的根节点x和y,新建一个节点new并把x和y的父亲设为new,new的点权则是新加入边的边权

    这样一个点u走海拔超过d的边能到的点就是其经过点权超过d的点能到的点,我们发现父亲的点权总是小于儿子,因此我们倍增找到u能到的深度最浅的祖先v,u能到的所有点就是v的子树

    #include<bits/stdc++.h>
    #define file(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout);
    #define P 998244353
    #define mid (l+r>>1)
    #define N 1100000
    #define lb(x) (x&(-x))
    #define inf 999999999
    #define M 1658561
    #define ll long long
    #define mem(x) memset(x,0,sizeof(x));
    using namespace std;
    int dis[N],f[N][21],ls,cnt,tot,n,m,T,Q,k,s,fa[N],to[N],nxt[N],head[N],w[N],mi[N],vis[N],p,d[N],v;
    struct edge{int x,y,w,d;}e[N];
    struct node{
        int id,dis;
        friend bool operator <(node x,node y){return x.dis>y.dis;}
    };
    priority_queue<node>q;
    bool cmp(edge x,edge y){ return x.d>y.d;}
    int find(int x){ return fa[x]==x? x:fa[x]=find(fa[x]);}
    void add(int x,int y,int z){
    //    printf("%d %d %d
    ",x,y,z);
        to[++cnt]=y;
        nxt[cnt]=head[x];
        head[x]=cnt;
        w[cnt]=z;
    }
    int dfs2(int x){
    //    printf("%d %d
    ",x,dis[x]);
        mi[x]=dis[x];
        for(int i=head[x];i;i=nxt[i])mi[x]=min(mi[x],dfs2(to[i]));
        return mi[x];
    }
    void dj(){
        memset(dis,0x3f,sizeof(dis));
        mem(vis);
        q.push({1,0});dis[1]=0;
        while(!q.empty()){
            int x = q.top().id;q.pop();
            if(vis[x]) continue; vis[x] = 1;
            for(int i=head[x];i;i=nxt[i]){
                if(dis[to[i]]>dis[x]+w[i]){
                    dis[to[i]]=dis[x]+w[i];
                    q.push({to[i],dis[to[i]]});
                }
            }
        }
    }
    int main(){
        //file("s");
        scanf("%d",&T);
        while(T--){
            mem(head);mem(d);ls=cnt=0;
            scanf("%d%d",&n,&m);
            for(int i=1;i<=m;i++) scanf("%d%d%d%d",&e[i].x,&e[i].y,&e[i].w,&e[i].d),add(e[i].x,e[i].y,e[i].w),add(e[i].y,e[i].x,e[i].w);
            dj();
            mem(head);cnt=0;
            scanf("%d%d%d",&Q,&k,&s);
            sort(e+1,e+m+1,cmp);tot=n;
            for(int i=1;i<=n;i++) fa[i]=i;
            for(int i=1;i<=m&&tot-n<n-1;i++){
                int x=find(e[i].x),y=find(e[i].y);
        //        printf("/%d %d/
    ",x,y);
                if(x==y) continue;
        //        printf("-%d %d-
    ",x,y);
                d[++tot]=e[i].d;
                fa[tot]=tot;
                add(tot,x,0);add(tot,y,0);
                fa[x]=f[x][0]=fa[y]=f[y][0]=tot;
            }
            for(int i=1;i<=20;i++) for(int j=1;j<=tot;j++) f[j][i]=f[f[j][i-1]][i-1];
            //printf("%d
    ",tot);
            dfs2(tot);
            //return 0;
            for(int i=1;i<=Q;i++){
                scanf("%d%d",&v,&p);
                v=(v+k*ls-1)%n+1;p=(p+k*ls)%(s+1);
                for(int i=20;~i;i--) if(d[f[v][i]]>p)v=f[v][i];
                printf("%d
    ",ls=mi[v]);
            }
        }
        return 0;
    }
  • 相关阅读:
    codeforces 1198B
    POJ 3177 Redundant Paths (tarjan边双连通分量)
    Geotrellis系列文章链接
    geotrellis使用(十一)实现空间数据库栅格化以及根据属性字段进行赋值
    geotrellis使用(十)缓冲区分析以及多种类型要素栅格化
    geotrellis使用(九)使用geotrellis进行栅格渲染
    geotrellis使用(八)矢量数据栅格化
    geotrellis使用(七)记录一次惨痛的bug调试经历以及求DEM坡度实践
    Parallel并行化编程
    geotrellis使用(六)Scala并发(并行)编程
  • 原文地址:https://www.cnblogs.com/blogoflyn/p/13257545.html
Copyright © 2020-2023  润新知