首页 > 其他分享 >[NOI2021] 庆典

[NOI2021] 庆典

时间:2023-09-05 12:01:31浏览次数:35  
标签:ch 游行 fa 庆典 城市 NOI2021 int Rightarrow

题目描述

C 国是一个繁荣昌盛的国家,它由 \(n\) 座城市和 \(m\) 条有向道路组成,城市从 \(1\) 到 \(n\) 编号。如果从 \(x\) 号城市出发,经过若干条道路后能到达 \(y\) 号城市,那么我们称 \(x\) 号城市可到达 \(y\) 号城市,记作 \(x\Rightarrow y\)。C 国的道路有一个特点:对于三座城市 \(x\),\(y\),\(z\),若 \(x\Rightarrow z\) 且 \(y\Rightarrow z\),那么有 \(x\Rightarrow y\) 或 \(y\Rightarrow x\)。

再过一个月就是 C 国成立的千年纪念日,所以 C 国的人民正在筹备盛大的游行庆典。目前 C 国得知接下来会有 \(q\) 次游行计划,第 \(i\) 次游行希望从城市 \(s_i\) 出发,经过若干个城市后,在城市 \(t_i\) 结束,且在游行过程中,一个城市可以被经过多次。为了增加游行的乐趣,每次游行还会临时修建出 \(k\)(\(0 \le k \le 2\))条有向道路专门供本次游行使用,即其它游行计划不能通过本次游行修建的道路。

现在 C 国想知道,每次游行计划可能会经过多少座城市

注意:临时修建出的道路可以不满足 C 国道路原有的特点

先缩点,反正不影响可达性。

在那个性质中,\(x\Rightarrow z\) 且 \(y\Rightarrow z\),那么 \(x\) 和 \(y\) 中有一个可达另一个,设 \(x\Rightarrow y\),那么此时如果 \(x\) 到 \(z\) 有边,我们可以删去 \(x\) 到 \(z\) 的边。

换言说,对于一个点的所有入边,我们只保留拓扑序最大的那条边(拓扑序应该是固定的),不影响可达性。所以现在变成了一棵树的问题。要在树上增加几条边后,判断有几个点既能被 \(s\) 到达又能到达 \(t\)。

当 \(k=0\) 和 \(k=1\) 时写个分讨就行了,但是 \(k=2\) 不该有人想写分讨吧。此时可以把 \(s\),\(t\) 和其他边的端点放在一起建出虚树,然后此时只有 \(O(k)\) 条边,用 bfs 求出可达性之后就好做了。

#include<bits/stdc++.h>
using namespace std;
const int N=6e5+5;
int n,m,q,k,tme,dfn[N],low[N],id[N],st[N],tp,idx,hd[N],e_num,u[N],v[N],rt,fa[N][23],dep[N],dp[N],s,t,ans,l=1,r,vs[2][N],sz[N],p[N];
struct edge{
	int v,nxt,f,w;
}e[N];
void add_edge(int u,int v,int f=0,int w=0)
{
	e[++e_num]=(edge){v,hd[u],f,w};
	hd[u]=e_num;
}
int read()
{
	int s=0;
	char ch=getchar();
	while(ch<'0'||ch>'9')
		ch=getchar();
	while(ch>='0'&&ch<='9')
		s=s*10+ch-48,ch=getchar();
	return s;
}
void topo()
{
	idx=0;
	for(int i=1;i<=tme;i++)
		if(!dfn[i])
			st[++r]=i;
	rt=st[1];
	while(l<=r)
	{
		for(int i=hd[st[l]];i;i=e[i].nxt)
		{
			--dfn[e[i].v];
			if(!dfn[e[i].v])
				fa[e[i].v][0]=st[l],st[++r]=e[i].v;
		}
		++l;
	}
}
void tarjan(int x)
{
	dfn[x]=low[x]=++idx,st[++tp]=x;
	for(int i=hd[x];i;i=e[i].nxt)
	{
		if(!dfn[e[i].v])
			tarjan(e[i].v),low[x]=min(low[x],low[e[i].v]);
		else if(!id[e[i].v])
			low[x]=min(low[x],dfn[e[i].v]);
	}
	if(dfn[x]==low[x])
	{
		++tme;
		while(st[tp]^x)
			sz[id[st[tp--]]=tme]++;
		sz[id[st[tp--]]=tme]++;
	}
}
int lca(int x,int y)
{
	if(dep[x]<dep[y])
		swap(x,y);
	for(int i=20;~i;--i)
		if(dep[fa[x][i]]>=dep[y])
			x=fa[x][i];
	if(x==y)
		return x;
	for(int i=20;~i;--i)
		if(fa[x][i]^fa[y][i])
			x=fa[x][i],y=fa[y][i];
	return fa[x][0];
}
void dfs(int x)
{
	dep[x]=dep[fa[x][0]]+1;
	dp[x]=dp[fa[x][0]]+sz[x];
	dfn[x]=++idx;
	for(int i=1;i<=20;i++)
		fa[x][i]=fa[fa[x][i-1]][i-1];
	for(int i=hd[x];i;i=e[i].nxt)
		dfs(e[i].v);
}
int cmp(int x,int y)
{
	return dfn[x]<dfn[y];
}
void clr(int x)
{
	hd[x]=vs[0][x]=vs[1][x]=0;
}
void sou(int x)
{
	if(vs[0][x]&&vs[1][x])
		ans+=sz[x];
	for(int i=hd[x];i;i=e[i].nxt)
	{
		if(!e[i].f&&!e[i].w)
		{
			sou(e[i].v);
			if(vs[0][x]&&vs[1][e[i].v])
				ans+=dp[fa[e[i].v][0]]-dp[x];
		}
	}
}
void bfs(int x,int op)
{
	low[l=r=1]=x;
	vs[op][x]=1;
	while(l<=r)
	{
		for(int i=hd[low[l]];i;i=e[i].nxt)
		{
			if(!vs[op][e[i].v]&&e[i].w==op)
			{
				vs[op][e[i].v]=1;
				low[++r]=e[i].v;
			}
		}
		++l;
	}
}
void addedge(int u,int v,int f=0)
{
	//printf("hjhyyds:%d %d\n",u,v);
		//printf("qzm:%d %d\n",u,v);
	add_edge(u,v,f,0);
	add_edge(v,u,f,1);
}
int main()
{
	n=read(),m=read(),q=read(),k=read();
	for(int i=1;i<=m;i++)
		u[i]=read(),v[i]=read(),add_edge(u[i],v[i]);
	for(int i=1;i<=n;i++)
		if(!dfn[i])
			tarjan(i);
	memset(hd,e_num=0,sizeof(hd));
	memset(dfn,0,sizeof(dfn));
	for(int i=1;i<=m;i++)
		if(id[u[i]]^id[v[i]])
			add_edge(id[u[i]],id[v[i]]),++dfn[id[v[i]]];
	topo();
	memset(hd,e_num=idx=0,sizeof(hd));
	for(int i=1;i<=tme;i++)
		if(i^rt)
			add_edge(fa[i][0],i);
	dfs(rt);
	while(q--)
	{
		int rt;
		scanf("%d%d",&s,&t),m=e_num=ans=0;
		p[++m]=id[s],p[++m]=id[t];
		//printf("%d %d\n",id[s],id[t]);
		for(int i=1;i<=k;i++)
		{
			scanf("%d%d",u+i,v+i);
			p[++m]=id[u[i]],p[++m]=id[v[i]];
			//printf("%d %d\n",id[u[i]],id[v[i]]);
		}
		sort(p+1,p+m+1,cmp);
		m=unique(p+1,p+m+1)-p-1;
		for(int i=1;i<=m;i++)
			clr(p[i]);
		clr(rt=st[tp=1]=lca(p[1],p[m]));
		for(int i=2;i<=m;i++)
			clr(lca(p[i-1],p[i]));
		for(int i=1;i<=m;i++)
		{
			if(p[i]==st[1])
				continue;
			int d=lca(p[i],st[tp]);
			if(d^st[tp])
			{
				while(dfn[d]<dfn[st[tp-1]])
					addedge(st[tp-1],st[tp]),--tp;
				if(d^st[tp-1])
					addedge(d,st[tp]),st[tp]=d;
				else
					addedge(d,st[tp--]);
			}
			st[++tp]=p[i];
		}
		for(int i=1;i<tp;i++)
			addedge(st[i],st[i+1]);
		for(int i=1;i<=k;i++)
			if(id[u[i]]^id[v[i]])
				addedge(id[u[i]],id[v[i]],1);
		bfs(id[s],0);
		bfs(id[t],1);
		sou(rt);
		printf("%d\n",ans);
	}
}

标签:ch,游行,fa,庆典,城市,NOI2021,int,Rightarrow
From: https://www.cnblogs.com/mekoszc/p/17679249.html

相关文章

  • [NOI2021] 轻重边题解
    题目传送门一眼数据结构考虑树上有什么数据结构支持\(x\)到\(y\)节点的修改和查询,那就是:树链剖分。那么这道树链剖分的题有个\(trick\):边点转换&染色法,对于每次修改,考虑将修改路径上的点全部染上一种独一无二的颜色,而查询的时候,就查询路径上相邻的相同的颜色节点个数即可......
  • 挖数据四周年庆典,壕礼不断,惊喜不停!
    挖数据四周岁啦!为了感谢广大用户们一路以来的支持与陪伴,我们特地准备了丰富的优惠活动,希望能够用最实际的行动来回馈您们的厚爱。四年的成长与蜕变,都是因为有您们的陪伴与鼓励,我们期待与您们一同分享这份喜悦与成功。 ......
  • 洛谷 P7739 - [NOI2021] 密码箱
    感觉难度和今年D2T2差不多。首先一个很显然的事情是,每一步得到的分数的分子分母都是互质的,证明参考SBT。而最后答案要求我们将分子分母都求出来而不是求分数值,所以可以很明显的想到将分数当成一个二元组然后维护变换。考虑从右往左扫,假设当前分数为\(\dfrac{x}{y}\),那么扫过......
  • [NOI2021] 路径交点 题解
    [NOI2021]路径交点题解题意给定一张\(k\)层的有向图,第\(i\)层有\(n_i\)​个顶点,第​\(1\)层与第\(k\)​层顶点数相同。对于第​​\(j\)\((1\leqj<k)\)层的顶点,只会连向第\(j+1\)层的顶点。没有边连向第\(1\)层的顶点,第\(k\)层的顶点不会向其他顶点连边......
  • 东方中科并购北汇仪式暨北汇周年庆典盛大举行!
    一场由于疫情推迟的庄重的并购仪式,一场由于疫情延误了三年的全公司周年聚会,终于在7月14日和15日,上海,东方中科并购北汇仪式暨北汇周年庆典,盛大举行了!并购是“新起点”,在新股东——东方中科支持下、新的战略规划指引下,北汇踏上“新征程”。来自东方中科的领导以及北汇信息全体员工,......
  • NOI2021 题解
    [NOI2021]轻重边转化一下题意:每次给一条链染色,查一条链从\(x\)到\(y\)有几条边两端颜色相同。那这个随便树剖线段树就好了。也可以LCT,码量可能要小点。#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<vector>usingnamespace......
  • 「NOI2021」庆典
    首先可以注意到题面中的这个条件:对于三座城市\(x\),\(y\),\(z\),若\(x\Rightarrowz\)且\(y\Rightarrowz\),那么有\(x\Rightarrowy\)或\(y\Rightarrowx\)。这就代表着如果存在边\(x\rightarrowz\)和\(y\rightarrowz\),假设存在\(x\Rightarrowy\)那么删去边\(x\r......
  • luogu P7740 [NOI2021] 机器人游戏
    题面传送门一个bitset值52分?首先样例让你容斥你就容斥,枚举哪些位是可以的,计算每一位的\(p_0,p_1,q_0,q_1\)表示是否被要求最后是\(0/1\),是否有最终值是开始值异或\(0/1\)。然后每个位置的贡献可以分类讨论出来:如果\(p_0,p_1\)或者\(q_0,q_1\)都有,那只能空着。如......
  • [P7738][NOI2021] 量子通信
    [NOI2021]量子通信题目背景由于评测性能差异,本题时限+0.5s。题目描述小Z正在自学量子计算机相关知识,最近他在研究量子通信章节,并遇到了一个有趣的问题。在该问题中,Alice和Bob正在进行量子通信,它们的通信语言是一个大小为\(n\)的字典\(S\),在该字典中,每一个单词\(s_i......
  • 奔赴山海 向阳而生|海泰方圆2022财年年会暨二十周年庆典盛大启动
    奔赴山海向阳而生·岁序更替,华章日新。从2003到2023,海泰走过二十年风雨岁月,在时代潮流中砥砺奋进,在密码产业中循梦而行,走出了极具特色的海泰发展之路。2023年2月28日-3月1......