Code Chef - Chef and Graph Queries

传送门

题目大意

给定一个$n$个点$m$条边的无向图$(n,m\leq 200000)$。

有$q$每次询问$(q\leq 200000)$,每次给定一个区间$L,R$,求仅保留编号$\in[L,R]$的边,原图连通块的数量。

题解

不难发现连通块数量可以通过总点数$-$最大生成森林的边集大小得到。

按照编号对边从小到大排序,用$LCT$动态维护最大生成森林,每次操作加边时,若两个点不连通,就直接连边即可。

否则,就把路径上编号最小的边断掉,再强行连上新的边。则当前的生成森林一定是最大的并且恰好覆盖了每一个连通块。

对于每一次询问,就是用$n$减去在最大的边编号为$R$时,最大生成森林中编号$\in[L,R]$的数量。

用主席树维护一下即可。复杂度$O((m+q)\log n)$。

由于在$LCT$中维护边权比较复杂,所以我们可以把一条边变成一个点,这个点连向原边的两段端点,点权即为边权,会方便许多。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define M 400020
#define INF 3000020
#define ls c[x][0]
#define rs c[x][1]
#define mid ((l+r)>>1)
using namespace std;
int read(){
	int nm=0,fh=1; char cw=getchar();
	for(;!isdigit(cw);cw=getchar()) if(cw==‘-‘) fh=-fh;
	for(;isdigit(cw);cw=getchar()) nm=nm*10+(cw-‘0‘);
	return nm*fh;
}
void write(int x){if(x>9) write(x/10);putchar(x%10+‘0‘);}
int n,m,fa[M],c[M][2],u[M],v[M],e[M],rev[M];
int L[M*30],R[M*30],sum[M*30],cnt,rt[M],S[M],top,tot;
void pushup(int x){if(x) e[x]=(x>n?x-n:INF),e[x]=min(e[x],min(e[ls],e[rs]));}
void pushdown(int x){if(rev[x]&&x) rev[x]=0,rev[ls]^=1,rev[rs]^=1,swap(ls,rs);}
bool isroot(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;}
void rotate(int x){
	int tp=fa[x],dtp=fa[fa[x]],ms,ds;
	if(c[dtp][0]==tp) c[dtp][0]=x;
	else if(c[dtp][1]==tp) c[dtp][1]=x;
	if(c[tp][0]==x) ms=0,ds=1;else ms=1,ds=0;
	fa[x]=dtp,fa[tp]=x,fa[c[x][ds]]=tp;
	c[tp][ms]=c[x][ds],c[x][ds]=tp;
	pushup(tp),pushup(x);
}
void splay(int x){
	S[top=1]=x;
	for(int y=x;!isroot(y);y=fa[y]) S[++top]=fa[y];
	while(top) pushdown(S[top]),top--;
	while(!isroot(x)){
		int tp=fa[x];
		if(isroot(tp)) return rotate(x);
		else if(c[c[fa[tp]][0]][0]==x) rotate(tp);
		else if(c[c[fa[tp]][1]][1]==x) rotate(tp);
		else rotate(x);
	}
}
int fdrt(int x){return fa[x]?fdrt(fa[x]):x;}
void access(int x){for(int y=0;x;y=x,x=fa[x]) splay(x),rs=y,pushup(x);}
void chroot(int x){access(x),splay(x),rev[x]^=1;}
void link(int x,int y){chroot(x),splay(x),fa[x]=y;}
void cut(int x,int y){chroot(x),access(y),splay(x),fa[y]=ls=rs=c[y][0]=c[y][1]=0,pushup(x),pushup(y);}
int qry(int x,int y){chroot(x),access(y),splay(x);return (fdrt(y)!=x)?0:e[x];}
void ins(int &x,int pre,int l,int r,int pos,int dt){
	x=++cnt,L[x]=L[pre],R[x]=R[pre];
	sum[x]=sum[pre]+dt; if(l==r) return;
	if(pos<=mid)ins(L[x],L[pre],l,mid,pos,dt);
	else ins(R[x],R[pre],mid+1,r,pos,dt);
}
int getans(int x,int l,int r,int minn){
	if(r<minn||!sum[x]) return 0; if(l>=minn) return sum[x];
	return getans(L[x],l,mid,minn)+getans(R[x],mid+1,r,minn);
}
int main(){
	for(int T=read(),Q;T;T--,cnt=0){
		n=read(),m=read(),Q=read(),tot=n,memset(c,0,sizeof(c));
		memset(rt,0,sizeof(rt)),memset(fa,0,sizeof(fa)),memset(e,0x3f,sizeof(e));
		for(int i=1;i<=m;i++){
			int now; u[i]=read(),v[i]=read(),rt[i]=rt[i-1],tot++;
			if(u[i]==v[i]) continue; now=qry(u[i],v[i]);
			if(now)	ins(rt[i],rt[i],1,m,now,-1),cut(u[now],v[now]);
			ins(rt[i],rt[i],1,m,i,1),link(u[i],tot),link(v[i],tot);
		}
		while(Q--){
			int tl=read(),tr=read(),num;
			num=getans(rt[tr],1,m,tl);
			write(n-num),putchar(‘\n‘);
		}
	}
	return 0;
}

原文地址:https://www.cnblogs.com/OYJason/p/9744840.html

时间: 2024-09-30 22:39:22

Code Chef - Chef and Graph Queries的相关文章

【CodeChef】Chef and Graph Queries

Portal --> CC Chef and Graph Queries Solution 快乐数据结构题(然而好像有十分优秀的莫队+可撤销并查集搞法qwq) 首先考虑一种方式来方便一点地..计算一个图的联通块数量:我们可以考虑容斥,维护每个连通块的生成树,然后\(n-\)生成树边数就是答案了 这样有一个好,加边的时候比较好处理,但是光这样并不能解决我们的问题 ? 顺着这个思路思考,先不考虑时间复杂度,对于一个询问,考虑将编号为\(l\sim r\)的边一条一条加入第\(1\sim l-1\)条

[CodeChef - GERALD07 ] Chef and Graph Queries

Read problems statements in Mandarin Chineseand Russian. Problem Statement Chef has a undirected graph G. This graph consists of N vertices and M edges. Each vertex of the graph has an unique index from 1 to N, also each edge of the graph has an uniq

[bzoj3514][CodeChef GERALD07] Chef ans Graph Queries [LCT+主席树]

题面 bzoj上的强制在线版本 思路 首先可以确定,这类联通块相关的询问问题,都可以$LCT$+可持久化记录解决 用LCT维护生成树作为算法基础 具体而言,从前往后按照边的编号顺序扫一遍边 如果这条边两端不在同一个$LCT$联通块中,则$link$ 否则$cut$掉当前连接两条边的路径上的编号最小的边,并$link$ 记录$ntr[i]$表示第$i$条边触发第二种情况时$link$前$cut$掉的边的编号 如果触发第一种情况,则$ntr[i]=0$ 如果为自环,则$ntr[i]=i$ 这样记录之

codechef AUG17 T1 Chef and Rainbow Array

Chef and Rainbow Array Problem Code: RAINBOWA Chef likes all arrays equally. But he likes some arrays more equally than others. In particular, he loves Rainbow Arrays. An array is Rainbow if it has the following structure: First a1 elements equal 1.

codechef AUG17 T2 Chef and Mover

Chef and Mover Problem Code: CHEFMOVR Chef's dog Snuffles has so many things to play with! This time around, Snuffles has an array A containing N integers: A1, A2, ..., AN. Bad news: Snuffles only loves to play with an array in which all the elements

运维神器Chef简单介绍和安装笔记

首先大概解释一下Chef Chef有三个重要的概念:(如上图所示) 它们的合作关系大致是这样的, Workstation把资源或者说是一些要被运行的命令上传到Chef-Server上, Nodes自动通过Chef-Server拿到属于自己的执行任务到本地执行,这样可达到一个将军指挥千军万马的效果:smirk:. Chef Server 存放所有通过Workstation上传的资源,和用户等公共数据(用PostgreSQL). 可以干脆叫它为资源服务器,大家都可以与它通讯(用RabbitMQ ),

自动化运维工具安装部署 chef (六)命令行总结

抽空继续chef的实验,理解了它的架构,测试环境重新推到重来 server yum install vsftpd -y vi /etc/vsftp/ftp_user vi /etc/vsftp/user_list systemctl stop firewalld systemctl disable firewalld setenforce 0 vi /etc/selinux/config systemctl restart vsftpd systemctl enable vsftpd vi /e

Chef 组件

Chef是一家自动化公司.自2008年成立以来,我们一直在将开发人员和系统管理员与我们的同名产品Chef Infra联系在一起.多年来,我们所说的自动化已经扩展了.今天,Chef为基础设施和应用程序提供了一个完整的自动化解决方案,可以将您从开发带到生产.这是完整的厨师解决方案. Git地址: https://github.com/chef/chef-web-docs Chef Infra Chef Infra是一个强大的自动化平台,可以将基础设施转换为代码.无论您是在云环境.本地环境还是混合环境

[LintCode] 618 Search Graph Nodes 解题报告

DescriptionGiven a undirected graph, a node and a target, return the nearest node to given node which value of it is target, return NULL if you can't find. There is a mapping store the nodes' values in the given parameters. NoticeIt's guaranteed ther