社区讨论

如果你树链剖分求LCA并TLE最后两个点

P4103[HEOI2014] 大工程参与者 2已保存回复 1

讨论操作

快速查看讨论及其快照的属性,并进行相关操作。

当前回复
1 条
当前快照
1 份
快照标识符
@lok08nc7
此快照首次捕获于
2023/11/04 20:12
2 年前
此快照最后确认于
2023/11/04 22:06
2 年前
查看原帖
那可能是你树链剖分写错退化成 O(n2)O(n^2) 了。
比如我在
CPP
#include<bits/stdc++.h>
#define DEBUG puts("嗯嗯谁也没看得起你");
using namespace std;
inline int read()
{
	int s=0,w=1;
	char c=getchar();
	while(c<'0'||c>'9')
	{
		if(c=='-')w=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9')s=(s<<3)+(s<<1)+(c^48),c=getchar();
	return s*w;
}
inline void print(long long x)
{
	if(x<0)x=-x,putchar('-');
	if(x>=10)print(x/10);
	putchar(x%10+48);
}
int n;
struct node
{
	int v,w,next;
}e[2000010],g[2000010];
int eid=1,head[1000010],Head[1000010],idx=1;
inline void insert(int u,int v)
{
	e[eid].v=v;
	e[eid].next=head[u];
	head[u]=eid++;
}
inline void add(int u,int v,int w)
{
	g[idx].v=v;
	g[idx].w=w;
	g[idx].next=Head[u];
	Head[u]=idx++;
}
int dfn[1000010],tot=0,si[1000010],son[1000010],f[1000010],top[1000010],id[1000010],dep[1000010];
inline void dfs(int u,int fa)
{
	si[u]=1;
	f[u]=fa;
	dep[u]=dep[fa]+1;
	for(int i=head[u];i;i=e[i].next)
	{
		int v=e[i].v;
		if(v==fa)continue;
		dfs(v,u);
		si[u]+=si[v];//
		if(si[son[u]]<si[v])son[u]=v;
	}
}
inline void dfs1(int u,int Top)
{
	top[u]=Top;
	dfn[u]=++tot;
	id[tot]=u;
	if(son[u])dfs1(son[u],Top);
	for(int i=head[u];i;i=e[i].next)
	{
		int v=e[i].v;
		if(v==f[u]||v==son[u])continue;
		dfs1(v,v);
	}
}
inline int lca(int a,int b)
{
	while(top[a]!=top[b])
	{
		if(dep[top[a]]<dep[top[b]])swap(a,b);
		a=f[top[a]];
	}
	return dep[a]<dep[b]?a:b;
}
const int inf=1e9;
int k,vis[1000010],a[1000010],siz[1000010],dp1[1000010],dp2[1000010],num,ma,mi;
long long ans=0;
inline bool cmp(int a,int b)
{
	return dfn[a]<dfn[b];
}
vector<int> ve;
inline void solve(int u,int fa)
{
	ve.push_back(u);
	siz[u]=vis[u];
	if(vis[u])
	dp1[u]=0;
	for(int i=Head[u];i;i=g[i].next)
	{
		int v=g[i].v,w=g[i].w;
		if(v==fa)continue;
		solve(v,u);
		siz[u]+=siz[v];
		ans=(ans+1ll*siz[v]*(k-siz[v])*w);
		mi=min(mi,dp1[u]+dp1[v]+w);
		dp1[u]=min(dp1[u],dp1[v]+w);
		ma=max(ma,dp2[u]+dp2[v]+w);
		dp2[u]=max(dp2[u],dp2[v]+w);
	}
}
signed main()
{
	n=read();
	for(int i=1;i<=n;i++)dp1[i]=inf;
	for(int i=1;i<n;i++)
	{
		int u=read(),v=read();
		insert(u,v);
		insert(v,u);
	}
	dfs(1,0);
	dfs1(1,1);
	int q=read();
	while(q--)
	{
		k=read();
		ans=0;
		ma=-inf;
		mi=inf;
		num=k;
		idx=1;
		ve.clear();
		for(int i=1;i<=k;i++)
		{
			a[i]=read();
			vis[a[i]]=1;
		}
		sort(a+1,a+num+1,cmp);
		for(int i=1;i<k;i++)a[++num]=lca(a[i],a[i+1]);
		sort(a+1,a+num+1,cmp);
		num=unique(a+1,a+num+1)-a-1;
		for(int i=2;i<=num;i++)
		{
			int LCA=lca(a[i],a[i-1]);
			add(LCA,a[i],dep[a[i]]-dep[LCA]);
			add(a[i],LCA,dep[a[i]]-dep[LCA]);
		}
		solve(a[1],0);
		for(int u:ve)vis[u]=0,Head[u]=0,dp1[u]=inf,dp2[u]=0;
		print(ans);
		putchar(' ');
		print(mi);
		putchar(' ');
		print(ma);
		puts("");
	}
}
没写注释处前一段代码,导致重儿子错误,不过仍然通过了 6,7,86,7,8 三个点的数据(数据为十万甚至一百万)。

回复

1 条回复,欢迎继续交流。

正在加载回复...