首页 > 其他分享 >圆方树学习笔记

圆方树学习笔记

时间:2023-02-23 19:11:49浏览次数:45  
标签:int back 笔记 yf 学习 圆方树 low dfn nyf

圆方树学习笔记

oi wiki

模板

void tarjan(int u)
{
	dfn[u]=low[u]=++ct; st[++tp]=u; tot++;
	for(int v:g[u])
		if(!dfn[v])
		{
			tarjan(v); low[u]=min(low[v],low[u]);
			if(low[v]>=dfn[u]) // 注意这里是 dfn[u]
			{
				nyf++; int x;
				do
				{
					x=st[tp--]; yf[nyf].push_back(x),yf[x].push_back(nyf); 
				} while(x!=v); // 注意这里是 v
				yf[nyf].push_back(u),yf[u].push_back(nyf); // 注意这里要把 u 也扔进去
			}
		}
		else low[u]=min(low[u],dfn[v]);	// 注意这里是 dfn
}

例题

[APIO2018] 铁人两项

https://www.luogu.com.cn/problem/P4630

转化成求路径并的点数,转成圆方树,记圆点权值 -1 方点权值点双大小,就可以转化成所有简单路径路径权值和,考虑统计每个点的贡献即可

代码

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e5+5;
int n,m;
vector<int> g[N],yf[N<<1];
int nyf,dfn[N],low[N],st[N],tp,ct;
int w[N<<1],sz[N<<1],tot;
void tarjan(int u)
{
	dfn[u]=low[u]=++ct; st[++tp]=u; w[u]=-1; tot++;
	for(int v:g[u])
		if(!dfn[v])
		{
			tarjan(v); low[u]=min(low[v],low[u]);
			if(low[v]>=dfn[u])
			{
				nyf++; int x;
				do
				{
					x=st[tp--]; yf[nyf].push_back(x),yf[x].push_back(nyf); w[nyf]++;
				} while(x!=v);
				yf[nyf].push_back(u),yf[u].push_back(nyf); w[nyf]++;
			}
		}
		else low[u]=min(low[u],dfn[v]);	
}
ll ans=0;
void dfs(int u, int prv)
{
	sz[u]=(u<=n);
	for(int v:yf[u]) if(v!=prv) dfs(v,u),ans+=2ll*sz[u]*sz[v]*w[u],sz[u]+=sz[v];
	ans+=2ll*sz[u]*(tot-sz[u])*w[u];
}
int main()
{
	scanf("%d%d",&n,&m); nyf=n;
	for(int i=1,u,v; i<=m; i++) scanf("%d%d",&u,&v),g[u].push_back(v),g[v].push_back(u);
	for(int i=1; i<=n; i++) if(!dfn[i]) ct=0,tot=0,tarjan(i),tp--,dfs(i,i);
	printf("%lld\n",ans);
	return 0;
}

P4606 [SDOI2018]战略游戏

https://www.luogu.com.cn/problem/P4606

转成圆方树上路径并的点集大小\(-\left| S\right|\)

求点集大小:把点权扔到上面的边,转化成树上走一遍的边权和的一半,把点集按 dfn 排序,两两求距离即可,注意特判最上面的点

代码

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e5+5, M = 2e5+5;
int _,n,m,q;
vector<int> g[N],yf[M];
int dfn[N],low[N],st[N],tp,dfc,nyf;
void tarjan(int u)
{
	dfn[u]=low[u]=++dfc; st[++tp]=u;
	for(int v:g[u])
		if(!dfn[v])
		{
			tarjan(v); low[u]=min(low[u],low[v]);
			if(low[v]>=dfn[u])
			{
				nyf++; for(int x; x!=v; tp--) x=st[tp],yf[nyf].push_back(x),yf[x].push_back(nyf);
				yf[nyf].push_back(u),yf[u].push_back(nyf);
			}
		}
		else low[u]=min(low[u],dfn[v]);
}
int dfn2[M],top[M],sz[M],d[M],f[M],hson[M],dfi2[M],fa[M];
void slpf1(int u, int prv)
{
	fa[u]=prv; sz[u]=1;
	for(int v:yf[u]) if(v!=prv)
	{
		d[v]=d[u]+1; f[v]=f[u]+(v<=n); slpf1(v,u); sz[u]+=sz[v];
		if(sz[v]>sz[hson[u]]) hson[u]=v;
	}
}
void slpf2(int u)
{
	dfn2[u]=++dfc; dfi2[dfn2[u]]=u; if(hson[u]) top[hson[u]]=top[u],slpf2(hson[u]);
	for(int v:yf[u]) if(v!=fa[u] and v!=hson[u]) top[v]=v,slpf2(v);
}
int lca(int u, int v)
{
	while(top[u]!=top[v])
	{
		if(d[top[u]]<d[top[v]]) swap(u,v);
		u=fa[top[u]];
	}
	return d[u]<d[v]?u:v;
}
int dist(int u, int v) { return f[u]+f[v]-(f[lca(u,v)]<<1); }
int p[N];
int main()
{
	scanf("%d",&_);
	while(_--)
	{
		scanf("%d%d",&n,&m);
		for(int i=1; i<=n; i++) g[i].clear(); for(int i=1; i<=(n<<1); i++) yf[i].clear();
		for(int i=1,u,v; i<=m; i++) scanf("%d%d",&u,&v),g[u].push_back(v),g[v].push_back(u);
		for(int u=1; u<=n; u++) dfn[u]=low[u]=0; dfc=tp=0; nyf=n; tarjan(1);
		for(int u=1; u<=nyf; u++) dfn2[u]=top[u]=sz[u]=d[u]=f[u]=hson[u]=dfi2[u]=fa[u]=0;
		dfc=0; slpf1(1,0); top[1]=1; slpf2(1);
		scanf("%d",&q); int s;
		while(q--)
		{
			scanf("%d",&s); for(int i=1; i<=s; i++) scanf("%d",&p[i]);
			sort(p+1,p+s+1, [&] (const int &a, const int &b) { return dfn2[a]<dfn2[b]; });
			int t=p[s]; ll ans=dist(p[s],p[1]);
			for(int i=1; i<s; i++) ans+=dist(p[i],p[i+1]),t=lca(t,p[i]);
			printf("%lld\n",(ans>>1)+(t<=n)-s);
		}
	}
	return 0;
}

标签:int,back,笔记,yf,学习,圆方树,low,dfn,nyf
From: https://www.cnblogs.com/copper-carbonate/p/17149108.html

相关文章

  • 关于tomCat 部署到阿里云linux中不能访问随笔记录
    一、首先查看服务器的端口号是否开放1.首先看一下服务器内部防火墙有没有开启以及有没有开启80或者8080端口号:命令:firewall-cmd--list-ports如有则显示如下图片:2.......
  • 2023.2.23软件工程学习日报
    所花时间:1.5小时代码量:100行博客量:1了解到的知识点:今天学习了在AndroidStudio中进行activity的跳转了解到的内容为:创建一个活动后一定要在项目中进行注册,注册完成后要......
  • 爬虫学习素材:国家中英文名对照表
    国家中英文对照表,做爬虫时可能会需要用到。我在去年做新冠肺炎疫情地图时用到了该素材,并且对其中发现的错误内容做了修正,可以满足小型项目使用。需要的朋友可以自取。nam......
  • webrtc QOS笔记二 音频buffer数据不足生成很多gap的问题
    webrtcQOS笔记二音频buffer数据不足生成很多gap的问题目录webrtcQOS笔记二音频buffer数据不足生成很多gap的问题记录个iusse.插入音频数据后,GetAudioInternal进......
  • docker 操作笔记
    1.Docker创建ubuntu系统更换apt-get源创建Dockerfile并且更新apt源在Dockerfile中添加如下两句代码:RUNsed-is@/archive.ubuntu.com/@/mirrors.aliyun.com/@g/et......
  • 第十四天笔记 正则
    第十四天笔记正则概述正则是用于检验对应的字符串的一种特殊表达式,一般用于用户格式验证正在对象声明使用//来声明(常用)vara=/a/ig//匹配修饰符console.log(reg......
  • uniapp vue3 setup开发笔记
    uniappvue3setup写法中使用onload,onshow等生命周期首先通过这种方式引入import{onShow,onHide,onLoad}from"@dcloudio/uni-app"和vue3普通生命周期一样的使用......
  • 声纹识别SR学习
    声纹模型基础训练、推理的流程框架ASV简介关联任务说话人日志(Speakerdiarisation)通过声纹识别把说话人身份表示出来,采访、庭审特定说话人分离(Targetspeakersep......
  • python学习笔记
    1.变量名称区分大小写(age、Age和AGE是三个不同的变量)2.在函数内部创建一个与全局变量同名的变量:x="awesome"defmyfunc():x="fantastic"print("Pythonis"......
  • 学习笔记——Nginx在linux中的命令
    2023-02-231、Nginx命令(1)开启Nginx安装Nginx之后,在“/usr/local/nginx/sbin”目录中sudo./nginx(2)关闭Nginx,在“/usr/local/nginx/sbin”目录中sudo./nginx-s......