zoukankan      html  css  js  c++  java
  • 「APIO2019」桥梁(询问分块+并查集)

    「APIO2019」桥梁(询问分块+并查集)

    询问每(S)个分块后,每次对于所有块内未被更改的边 及 所有询问 排序,然后依次加入并查集,这一部分复杂度为(O(m frac{q}{S}(log m+alpha(n))))

    对于(S)条被改变的边,对于每个询问分别考虑这些边的贡献,复杂度为(O(qS)),由于涉及到并查集回撤的问题,可以使用按秩合并,复杂度为(O(qSlog S))

    按照上面两步暴力实现,复杂度大概可以做到(O((m+q)sqrt{q}log n))

    实际可行的优化有:

    用平衡树实现排序,每次暴力遍历,第一部分复杂度降为(O(qlog m+mfrac{q}{S} alpha(n)))

    由于最多访问到(O(S))个联通块,第二部分用(dfs)遍历来实现,复杂度降为(O(q S alpha(n)))(遍历过程中要访问联通块编号)

    复杂度可以降到约(O((m+q)sqrt {q} cdot alpha(n)))

    以下是暴力实现的代码

    #include<bits/stdc++.h>
    using namespace std;
    #define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
    #define drep(i,a,b) for(int i=a,i##end=b;i>=i##end;--i)
    #define pb push_back
    char IO;
    int rd(){
    	int s=0;
    	while(!isdigit(IO=getchar()));
    	do s=(s<<1)+(s<<3)+(IO^'0');
    	while(isdigit(IO=getchar()));
    	return s;
    }
    
    const int N=1e5+10;
    int n,m,S,q,qc;
    struct Edge{
    	int u,v,w;
    	bool operator < (Edge __) const { return w<__.w; }
    } A[N],B[N],Q[N];
    struct Node{ int t,w; };
    vector <Node> G[N];
    int uid[N],uc,fa[N],sz[N],ux[N],uy[N],rc,ans[N];
    int Find(int x){ while(fa[x]!=x) x=fa[fa[x]]; return x; }
    void Union(int x,int y){
    	x=Find(x),y=Find(y);
    	if(x==y) return;
    	if(sz[x]>sz[y]) swap(x,y);
    	ux[++rc]=x,uy[rc]=y;
    	fa[x]=y,sz[y]+=sz[x]; // 按秩合并用于回撤
    }
    
    int main(){
    	n=rd(),m=rd();
    	rep(i,1,m) A[i].u=rd(),A[i].v=rd(),A[i].w=rd();
    	S=sqrt(3*(n+m));
    	rep(i,1,q=rd()) {
    		ans[i]=-1;
    		int opt=rd(),x=rd(),y=rd();
    		if(opt==1) G[x].pb((Node){i,y});
    		else Q[++qc]=(Edge){i,x,y};
    		if(qc%S==0 || i==q) {
    			if(!qc) continue;
    			int c=0;
    			rep(i,1,m) if(!G[i].size()) B[++c]=A[i];
    			else uid[++uc]=i;
    			sort(B+1,B+c+1),sort(Q+1,Q+qc+1);
    			rep(i,1,n) fa[i]=i,sz[i]=1;
    			int p=c;
    			drep(i,qc,1) {
    				while(p && B[p].w>=Q[i].w) Union(B[p].u,B[p].v),p--;
    				rc=0;
    				rep(j,1,uc) {
    					int x=uid[j],w=A[x].w;
    					for(auto k:G[x]) if(k.t<=Q[i].u) w=k.w;
    					else break; // 找到询问时这条边的权值
    					if(w>=Q[i].w) Union(A[x].u,A[x].v);
    				}
    				ans[Q[i].u]=sz[Find(Q[i].v)];
    				drep(j,rc,1) fa[ux[j]]=ux[j],fa[uy[j]]=uy[j],sz[uy[j]]-=sz[ux[j]];// 回撤
    				rc=0;
    			}
    			rep(i,1,uc) A[uid[i]].w=G[uid[i]].rbegin()->w,G[uid[i]].clear();
    			uc=qc=0;
    		}
    	}
    	rep(i,1,q) if(~ans[i]) printf("%d
    ",ans[i]);
    }
    
    
  • 相关阅读:
    在android 5.0以上,如何判断当前应用是在前台还是后台
    Android实现手机摄像头的自动对焦
    抓包获取百度音乐API
    andriod 自定义来电界面功能
    Android 自定义相机
    解决Android拍照保存在系统相册不显示的问题
    有关Color和Drawable你所不知道的那些内容
    Android主题切换方案总结
    设置background属性使用selector的时候内置?attr报错的解决方案
    一步一步解析google camera2 demo(三)
  • 原文地址:https://www.cnblogs.com/chasedeath/p/13380195.html
Copyright © 2011-2022 走看看