首页 > 其他分享 >题解 P4630 [APIO2018] 铁人两项

题解 P4630 [APIO2018] 铁人两项

时间:2023-11-10 11:14:55浏览次数:39  
标签:P4630 last 子树内 int 题解 APIO2018 三元组 low st

具体思路

题目问的是三元组 \((x,z,y)\) 使得 \(x\) 可以到达 \(z\),且 \(z\) 可以到达 \(y\),求三元组 \((x,z,y)\) 的数量。

我们转化一下问题,就是问 \(x,y\) 之间所有不重复路径的点的并集减 \(2\)。

显然,无向图中任意一个点都属于一个点双连通分量。

那么问题转化为 \(x,y\) 之间所有点双联通分量的并集减 \(2\)。

由于无向图中统计路径很难,而如果是树上问题,我们就可以树形 dp 了,于是考虑转化为树上问题。

那么需要建圆方树。

我们建好圆方树后,由于要求点双连通分量的并集,我们考虑给方点赋上点权,点权就是点双连通分量的大小。

但是这样会算重,因为一个割点可能并不只属于一个点双连通分量,因此我们需要给每个圆点在赋上 \(-1\) 的点权,就可以避免算重的问题了。

那么问题又转化为任意两个圆点之间的路径权值和。

直接计算的话时间复杂度为 \(O(n^2)\),我们不满足于此,需要优化。

考虑计算每个点的贡献,显然就是这个点的权值乘上这个点被经过的次数。

考虑树形 dp。

image

我们令 \(x\) 为三元组的中间点,\(y\) 为三元组的终点,\(st\) 为三元组的起点。

我们强制让 \(y\) 在子树内,那么此时 \(st\) 可以在 \(y\) 前面的子树内,也可以是 \(x\) 上面其他子树内。

其实这里 \(st\) 可以在 \(y\) 后面的子树内,但是为了不算重,我们只计算前面的贡献,最后 \(\times 2\)即可。

  • 若 \(st\) 在 \(y\) 前面的子树内,\(val=w_x \times siz_{前面子树} \times siz_y\)。

  • 若 \(st\) 在 \(x\) 上面其他子树内, \(val=w_x \times (siz_{整颗子树} - siz_x)\)。

最后记得所有节点的贡献乘以二即可。

Code

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e5+5,M=2e5+5;
int n,m;
struct edge{
	int x,y,pre;
}a[2*M];
int last[N],alen;
void ins(int x,int y){
	a[++alen]=edge{x,y,last[x]};
	last[x]=alen;
}
int dfn[N],low[N],id;
int top,sta[N];
int cnt,tot;LL w[2*N];
vector<int>G[2*N];
void tarjan(int x){
	tot++;
	dfn[x]=low[x]=++id;
	sta[++top]=x;
	w[x]=-1;
	for(int k=last[x];k;k=a[k].pre){
		int y=a[k].y;
		if(!dfn[y]){
			tarjan(y);
			low[x]=min(low[x],low[y]);
			if(dfn[x]<=low[y]){
				cnt++;
				int z;
				do{
					z=sta[top--];
					G[cnt].push_back(z);
					G[z].push_back(cnt);
					w[cnt]++;
				}while(z!=y);
				G[cnt].push_back(x);
				G[x].push_back(cnt);
				w[cnt]++;
			}
		}
		else low[x]=min(low[x],dfn[y]);
	}
}
LL siz[2*N],ans=0;
void dfs(int x,int fa){
	if(x<=n)siz[x]=1;
	for(int y:G[x]){
		if(y==fa)continue;
		dfs(y,x);
		ans=ans+2*siz[x]*siz[y]*w[x];
		siz[x]=siz[x]+siz[y];
	}
	ans=ans+2*siz[x]*(tot-siz[x])*w[x];
}
int main(){
	scanf("%d%d",&n,&m);
	alen=1;memset(last,0,sizeof(last));
	for(int i=1;i<=m;i++){
		int x,y;scanf("%d%d",&x,&y);
		ins(x,y),ins(y,x);
	}
	cnt=n;
	for(int i=1;i<=n;i++){
		if(!dfn[i]){
			tot=0;
			tarjan(i);
			dfs(i,0);
		}
	}
	printf("%lld",ans);
	return 0;
}

标签:P4630,last,子树内,int,题解,APIO2018,三元组,low,st
From: https://www.cnblogs.com/reclusive2007/p/17823622.html

相关文章

  • [题解] P6773 [NOI2020] 命运
    P6773[NOI2020]命运给你一棵\(n\)个节点的树,要给每条边染成\(0\)或\(1\)。有\(m\)个限制\((u,v)\)满足\(u\)是\(v\)祖先,表示\(u\)到\(v\)的路径中至少有一条边被染成了1。求方案数。\(n,m\le5\times10^5\)。首先会想到容斥,但是很没前途,所以考虑......
  • P9194 [USACO23OPEN] Triples of Cows P 题解
    Description给定一棵初始有\(n\)个点的树。在第\(i\)天,这棵树的第\(i\)个点会被删除,所有与点\(i\)直接相连的点之间都会两两连上一条边。你需要在每次删点发生前,求出满足\((a,b)\)之间有边,\((b,c)\)之间有边且\(a\not=c\)的有序三元组\((a,b,c)\)对数。\(n\leq2......
  • [题解] CF938G Shortest Path Queries
    ShortestPathQueries给你一张无向连通图,支持三种操作:插入一条边\((u,v,w)\)。删除一条边。求\((u,v)\)之间的异或最短路。\(n,m,1<2^{30}\)。先考虑异或最短路怎么求,这部分和最大XOR和路径是一样的。就是把图上的环都扔到一个线性基里,每次查询就是线性基......
  • [题解] P5901 [IOI2009] Regions
    P5901[IOI2009]Regions给你一棵树,每个点有颜色\(h_i\)。多次询问,每次询问有多少对\((u,v)\)满足\(u\)是\(v\)的祖先且\(u\)的颜色是\(r_1\)且\(v\)的颜色是\(r_2\)。\(n,q\le2\times10^5,h_i\le2.5\times10^4\)。总颜色数一定,考虑对颜色的出现次......
  • [题解] CFgym103069G Prof. Pang's sequence
    G.Prof.Pang'ssequence给一个长度为\(n\)的序列\(a\),多次询问区间\([l,r]\)内有多少个子区间的颜色数是奇数。\(n,m\le10^5\)。先按照HH的项链的套路,对于每个数记一下\(lst_i\)表示\(a_i\)上一次出现的位置。然后扫描线,将所有子区间的答案转化成历史和。......
  • [CSP-J 2021] 小熊的果篮 题解
    题目链接既然只有两种东西,我们不妨分开考虑,这里也借鉴了很多二分图题目的切入点。假设苹果和桔子下标分别如下图所示:苹果:1367910桔子:2458那么第一次取,应该是这样取:1234689也就是先取开头比较小的,然后轮流取,注意一定保证递增,也就是对于苹果找出来的\(x\)......
  • [题解]CFgym103470E Paimon Segment Tree
    PaimonSegmentTree区间加,求一段时间内的区间平方和。\(n,m,q\le5\times10^4\)。对时间维差分一下,变成询问区间历史平方和。离线下来扫描线,扫描线维护时间维,数据结构维护序列维。考虑维护二元组\((a,s)\)表示当前位置值为\(a\),历史平方和为\(s\)。可以发现怎......
  • A2OJ Ladder 21 简要题解
    https://earthshakira.github.io/a2oj-clientside/server/Ladder21.html只记录Difficultylevel>=8的。有很多题是口胡的。写了的会标注提交记录。还有些很久以前写过的题就懒得搬提交记录了。71.CF444EDZYlovesplanting我们二分答案,然后可以这样转化:把权\(\ged\)的......
  • 题解:疯狂lcm
    %你赛打到一半来写个题解link:疯狂lcm题意,求:\[\sum_{i=1}^{n}lcm(i,n)\]不多说废话,直接开推:\[\begin{aligned}&=n\sum_{i=1}^{n}\frac{i}{gcd(i,n)}\\&=n\sum_{d\midn}\sum_{i=1}^{n}\frac{i}{d}[gcd(i,n)=d]\\&=n\sum_{d\midn}\sum_{i=1}^{n}......
  • KubeEdge部署 完美运行 附问题解决方法
    云端部署环境准备一、部署前工作(k8s、docker安装及配置、初始化集群、golang安装、keadm安装)配置网络参数cat>>/etc/hosts<<EOF#GitHubStart52.74.223.119github.com192.30.253.119gist.github.com54.169.195.247api.github.com185.199.111.153assets-cdn.gith......