• 「NOI2018」归程 (Kruskal 重构树/持久化并查集)


    「NOI2018」归程 (Kruskal 重构树/持久化并查集)

    题意:每次查询仅通过边权\(\leq k\)能够到达的点中,距离根最近的

    离线做法:直接并查集维护当前\(\leq k\)边权的情况

    强制在线当然可以直接可持久化并查集

    持久化并查集非常麻烦,但是我们这里不需要进行回退操作,所以不需要可持久化

    Kruskal重构树:按照边权检出生成树,每次合并两个点就新建一个点向他们连边,最后得到的点就是根

    构建的重构树边权是单调的,每次能够到达的点是一个子树,倍增维护二分,子树预处理答案

    const int N=2e5+10,M=4e5+10;
    
    int n,m;
    struct Edge{
    	int to,nxt,w;
    }e[M<<1];
    int head[N],ecnt;
    void AddEdge(int u,int v,int w){
    	e[++ecnt]=(Edge){v,head[u],w};
    	head[u]=ecnt;
    }
    
    struct DijNode{
    	int x,d;
    	bool operator < (const DijNode __) const {
    		return d>__.d;
    	}
    };
    priority_queue <DijNode> que;
    int dis[N];
    void Dijkstra(){
    	rep(i,1,n) dis[i]=2e9;
    	que.push((DijNode){1,dis[1]=0});
    	while(!que.empty()) {
    		DijNode now=que.top(); que.pop();
    		int u=now.x;
    		if(now.d>dis[u]) continue;
    		for(int i=head[u];i;i=e[i].nxt) {
    			int v=e[i].to,w=e[i].w;
    			if(dis[v]>dis[u]+w) dis[v]=dis[u]+w,que.push((DijNode){v,dis[v]});
    		}
    	}
    }
    
    struct NODE{
    	int u,v,w;
    	bool operator < (const NODE __) const {
    		return w<__.w;
    	}
    } E[M];
    int bfa[N<<1],fa[20][N<<1],mi[N<<1],W[N<<1];
    int Find(int x){ return x==bfa[x]?x:bfa[x]=Find(bfa[x]); }
    
    int q,S,k,tn;
    
    int main(){
    	//freopen("return.in","r",stdin),freopen("return.out","w",stdout);
    	rep(kase,1,rd()) {
    		n=rd(),m=rd();
    		rep(i,1,n) head[i]=0; ecnt=0;
    		rep(i,1,m) {
    			int u=rd(),v=rd(),l=rd(),a=rd();
    			E[i]=(NODE){u,v,a};
    			AddEdge(u,v,l);
    			AddEdge(v,u,l);
    		}
    		Dijkstra();
    		rep(i,1,n*2) bfa[i]=i,fa[0][i]=0;
    		rep(i,1,tn=n) mi[i]=dis[i];
    		sort(E+1,E+m+1);
    		drep(i,m,1) {
    			int x=E[i].u,y=E[i].v,w=E[i].w;
    			x=Find(x),y=Find(y);
    			if(x==y) continue;
    			fa[0][x]=fa[0][y]=bfa[x]=bfa[y]=++n;
    			mi[n]=min(mi[x],mi[y]);
    			W[n]=w;
    		}
    		rep(i,1,18) rep(j,1,n) fa[i][j]=fa[i-1][fa[i-1][j]];
    		q=rd(),k=rd(),S=rd();
    		int lst=0;
    		rep(i,1,q) {
    			int x=(rd()+k*lst-1)%tn+1,p=(rd()+k*lst)%(S+1);
    			drep(j,18,0) if(fa[j][x] && W[fa[j][x]]>p) x=fa[j][x];
    			printf("%d\n",lst=mi[x]);
    		}
    	}
    }
    
    
  • 相关阅读:
    让Flask-admin支持markdown编辑器
    单例模式
    【Python】关于如何判断一个list是否为空的思考
    【Python】抽象工厂模式
    【Python篇】工厂模式
    【Python】直接赋值,深拷贝和浅拷贝
    【Python】可变对象和不可变对象
    【Python】__name__ 是什么?
    【Python】any() 或者 or
    [Python] list vs tupple
  • 原文地址:https://www.cnblogs.com/chasedeath/p/12724185.html
Copyright © 2020-2023  润新知