zoukankan      html  css  js  c++  java
  • #3145. 「APIO 2019」桥梁

    #3145. 「APIO 2019」桥梁

    题目描述

    圣彼得堡市内所有水路长度总和约 282 千米,市内水域面积占城市面积的 7%。——来自维基百科

    圣彼得堡位于由 (m) 座桥梁连接而成的 (n) 个岛屿上。岛屿用 (1)(n) 的整数编号,桥梁用 (1)(m) 的整数编号。每座桥连接两个不同的岛屿。有些桥梁是在彼得大帝时代建造的,其中一些是近期建造的。这导致了不同的桥梁可能有不同的重量限制。更具体地,只有重量不超过 (d_i) 的汽车才能通过第 (i) 座桥梁。有时圣彼得堡的一些桥梁会进行翻新,但这并不一定会使桥梁承重变得更好,也就是说,进行翻新的桥梁的 (d_i) 可能会增加或减少。你准备开发一个产品,用于帮助公民和城市客人。目前,你开发的模块要能执行两种类型的操作:

    1. 将桥梁 (b_j) 的重量限制改为 (r_j)

    2. 统计一辆重为 (w_j) 的汽车从岛屿 (s_j) 出发能够到达多少个不同的岛屿。

    请你回答所有第二种操作的答案。

    输入格式

    第一行包含两个整数 (n)(m)——表示圣彼得堡的岛屿数量与桥梁数量。

    接下来 (m) 行,每行三个整数 (u_i, v_i, d_i)。第 (i) 行的整数描述了一座连接岛屿 (u_i)(v_i),初始时重量限制为 (d_i) 的桥梁。

    接下来一行一个整数 (q)——表示操作的数量。

    接下来 (q) 行按顺序每行描述一个操作。

    每行第一个整数 (t_j) 表示操作类型:

    - 若 (t_j = 1),则该操作是第一种类型,该行接下来给定两个整数 (b_j)(r_j),表示桥梁 (b_j) 的重量限制将变为 (r_j)

    - 若 (t_j = 2),则该操作是第二种类型,该行接下来给定两个整数 (s_j)(w_j),表示一辆重为 (w_j) 的汽车将要从第 (s_j) 个岛屿出发。

    输出格式

    对于每个第二种类型的询问,输出一行一个整数表示答案。

    数据范围与提示

    对于全部数据,(1le nle 5 imes 10^4,0le mle 10^5,1le qle 10^5)。保证 (1le u_i,v_i,s_jle n,u_i ot =v_i,1le d_i,r_j,w_jle 10^9,1le b_jle m,t_jin{1,2})


    我们把一次修改视作产生了两条不同的边,每条边都有一个存在的时间。

    将操作序列分块,对每个块内的询问分别处理。将询问的(w)升序排列,将出现在这个块之前,并且在这个块之后再消失的边按(w)排序。依次处理询问时,依次加入这些边,用路径压缩的并查集。每一次询问时,对于结束时间在这个块内的边,我们暴力判断是否要加入,询问了之后再撤销。这部分用按秩合并的并查集。

    复杂度(O(msqrt{mlog(n)}))

    代码:

    #include<bits/stdc++.h>
    #define ll long long
    #define N 100005
    
    using namespace std;
    inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}
    
    int n,m,q;
    
    const int blk=600;
    int bel[N];
    struct edge {
    	int x,y,w;
    	int l,r;
    	bool operator <(const edge &a)const {return w>a.w;}
    }e[N<<1];
    bool cmpe(int a,int b) {
    	return e[a].w>e[b].w;
    }
    int etot;
    int lst[N];
    int op[N];
    int E[N],pos[N],w[N];
    vector<int>que[N/blk+5];
    bool cmp(int a,int b) {return w[a]>w[b];}
    
    int fa[N],size[N],dep[N];
    int Getf(int v) {return v==fa[v]?v:fa[v]=Getf(fa[v]);}
    
    int Getf2(int v) {
    	while(v!=fa[v]) v=fa[v];
    	return v;
    }
    
    void Merge(int a,int b) {
    	a=Getf(a),b=Getf(b);
    	if(a==b) return ;
    	fa[a]=b;
    	size[b]+=size[a];
    }
    
    void Init() {for(int i=1;i<=n;i++) fa[i]=i,size[i]=1,dep[i]=1;}
    vector<int>tem;
    int L[N],R[N];
    struct node {
    	int x,size,dep;
    	node() {}
    	node(int _x,int _size,int _dep) {x=_x,size=_size,dep=_dep;}
    };
    vector<node>undo;
    vector<int>st,st2;
    int ans[N];
    void Merge(vector<int>&a,vector<int>&b) {
    	static vector<int>st;
    	st.clear();
    	int ta=0,tb=0;
    	while(ta!=a.size()||tb!=b.size()) {
    		if(ta==a.size()) st.push_back(b[tb]),tb++;
    		else if(tb==b.size()) st.push_back(a[ta]),ta++;
    		else if(e[a[ta]].w>e[b[tb]].w) st.push_back(a[ta]),ta++;
    		else st.push_back(b[tb]),tb++;
    	}
    	a.clear();
    	for(int i=0;i<st.size();i++) a.push_back(st[i]);
    }
    int main() {
    	n=Get(),m=Get();
    	for(int i=1;i<=m;i++) {
    		e[i].x=Get(),e[i].y=Get(),e[i].w=Get();
    	}
    	q=Get();
    	for(int i=1;i<=m;i++) {
    		lst[i]=i;
    		e[i].l=1,e[i].r=q;
    	}
    	etot=m;
    	int x,y;
    	for(int i=1;i<=q;i++) {
    		op[i]=Get();
    		x=Get(),y=Get();
    		if(op[i]==1) {
    			E[i]=++etot;
    			e[E[i]]=e[lst[x]];
    			e[E[i]].w=y;
    			e[lst[x]].r=i-1;
    			e[E[i]].l=i;
    			e[E[i]].r=q;
    			lst[x]=etot;
    		} else {
    			pos[i]=x,w[i]=y;
    		}
    	}
    	sort(e+1,e+1+m);
    	for(int i=1;i<=m;i++) if(e[i].r) st.push_back(i);
    	for(int i=1;i<=q;i++) bel[i]=(i-1)/blk+1;
    	for(int i=1;i<=bel[q];i++) L[i]=(i-1)*blk+1,R[i]=min(q,i*blk);
    	for(int i=1;i<=q;i++) if(op[i]==2) que[bel[i]].push_back(i);
    	
    	for(int i=1;i<=bel[q];i++) {
    		sort(que[i].begin(),que[i].end(),cmp);
    		Init();
    		 
    		tem.clear();
    		for(int j=L[i];j<=R[i];j++) if(op[j]==1) tem.push_back(E[j]);
    		int tag=0;
    		for(int j=0;j<que[i].size();j++) {
    			int now=que[i][j];
    			while(tag<st.size()&&e[st[tag]].w>=w[now]) {
    				if(e[st[tag]].r>=R[i]) {
    					Merge(e[st[tag]].x,e[st[tag]].y);
    				} else if(e[st[tag]].r>=L[i]) tem.push_back(st[tag]);
    				tag++;
    			}
    			for(int k=0;k<tem.size();k++) {
    				int x=e[tem[k]].x,y=e[tem[k]].y;
    				Getf(x),Getf(y);
    			}
    			undo.clear();
    			for(int k=0;k<tem.size();k++) {
    				int id=tem[k];
    				if(e[id].l<=now&&now<=e[id].r&&e[id].w>=w[now]) {
    					int x=Getf2(e[id].x),y=Getf2(e[id].y);
    					if(x==y) continue ;
    					undo.push_back(node(x,size[x],dep[x]));
    					undo.push_back(node(y,size[y],dep[y]));
    					if(dep[x]>dep[y]) swap(x,y);
    					fa[x]=y;
    					size[y]+=size[x];
    					if(dep[x]==dep[y]) dep[y]++;
    				}
    			}
    			ans[now]=size[Getf2(pos[now])];
    			while(undo.size()) {
    				node a=undo.back();
    				undo.pop_back();
    				fa[a.x]=a.x;
    				size[a.x]=a.size;
    				dep[a.x]=a.dep;
    			}
    		}
    		st2.clear();
    		for(int j=L[i];j<=R[i];j++) if(op[j]==1) st2.push_back(E[j]);
    		sort(st2.begin(),st2.end(),cmpe);
    		Merge(st,st2);
    	}
    	for(int i=1;i<=q;i++) if(ans[i]) {
    		cout<<ans[i]<<"
    ";
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    最长公共子串
    Windows 下GitHub 安装和使用
    JSON 解析
    利用bootsrap控件 实现文件上传功能
    CCF 工资计算
    Java 对象引用以及对象赋值
    Java 关于创建String对象过程的内存分配
    JAVA堆内存和栈内存初步了解
    URAL 1152. False Mirrors (记忆化搜索 状压DP)
    POJ 1113 Wall(Graham求凸包周长)
  • 原文地址:https://www.cnblogs.com/hchhch233/p/11096931.html
Copyright © 2011-2022 走看看