题解 [UR #7] 水题走四方

传送门

啥也不会.jpg

首先因为不能往回走
所以肯定是一个人先把别的子树走完
尝试令 \(f_i\) 为仅剩 \(i\) 中子树没走的最小步数
发现可能出现剩一个子树和一条链,两者同时往下走的情况
发现这种情况下剩的链一定是子树内最长链
一个想法是让走子树的走到第一个有 \(>1\) 个儿子的地方停下等走链的走完了传送过来
但是是假的,题解有形象的解释
尝试修一修
考虑若最终走到了一个叶子 \(i\)
那么根到 \(i\) 的链上会有若干个关键点使得在那个点时,有一个人去处理这个关键点到下一个关键点之间的所有其它叶子了
那么就可以 DP 了,在每个点向上枚举上一个关键点在哪
复杂度 \(O(n^2)\)

然后这个东西有很多转移其实是无用的
就不复读题解了
大意是发现有些关键点一定不如其它的优
可以单调栈维护可能最优的关键点
然后利用处理以某个点为根的子树时只会 push 最大值和次大值
均摊下来 push 和 pop 次数是 \(O(n)\) 级别的

然后还有一种比较容易的做法是
经过分析可知只有每个点上方最近的满足 其它子树内最深的叶子比这个点深 的转移点是有用的
那么这个点可以在 dfs 时顺便求出来
具体的,对每个子树用链表维护还没有找到转移点的点,合并子树的时候互相更新一下就行了
有点卡空间,如果你 dfs 是递归实现还非要用 list<int> 的话
发现 dfs 序可以用输入的括号求出来,list<int> 也可以换成 forward_list<int>
那么就可以卡过了,复杂度 \(O(n)\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f3f3f3f3f
#define N 5000010
#define pb push_back
#define ll long long
//#define int long long

int n;
char s[N<<1];
forward_list<int> lis[N];
ll dis[N], f[N], ans=INF;
int dep[N], mdep[N], cnt[N];
int fa[N], head[N], bel[N], sta[N], deg[N], top, ecnt;
struct edge{int to, next;}e[N];
inline void add(int s, int t) {e[++ecnt]={t, head[s]}; head[s]=ecnt;}

signed main()
{
	// cout<<double(sizeof(lis)+sizeof(s)+sizeof(dep)*10+sizeof(dis)*2)/1000/1000<<endl;
	scanf("%d%s", &n, s+1);
	// scanf("%d", &n);
	// for (int i=2; i<=n; ++i) scanf("%d", &fa[i]);
	memset(f, 0x3f, sizeof(f));
	memset(head, -1, sizeof(head));
	for (int i=1,v=0,tot=0,now=0; i<=n*2; ++i)
		if (s[i]=='(') fa[++tot]=v, dep[sta[++top]=v=tot]=++now;
		else v=fa[v], --now;
	for (int i=2; i<=n; ++i) add(fa[i], i), ++deg[fa[i]]; //, cout<<fa[i]<<' '<<i<<endl;
	// bel[1]=1; dfs(1);
	// while (lis[1].size()) bel[lis[1].front()]=1, lis[1].pop_front();
	f[1]=0; bel[1]=1;
	for (int i=top; i; --i) {
		int u=sta[i];
		mdep[u]=dep[u];
		cnt[u]=(head[u]==-1);
		for (int i=head[u],v; ~i; i=e[i].next) {
			v = e[i].to;
			while (!lis[v].empty() && mdep[u]>=dep[lis[v].front()])
				bel[lis[v].front()]=u, lis[v].pop_front();
			while (!lis[u].empty() && mdep[v]>=dep[lis[u].front()])
				bel[lis[u].front()]=u, lis[u].pop_front();
			if (lis[u].empty()) swap(lis[u], lis[v]);
			mdep[u]=max(mdep[u], mdep[v]);
			dis[u]+=dis[v]+cnt[v];
			cnt[u]+=cnt[v];
		}
		lis[u].push_front(u);
	}
	for (int i=1,x,y; i<=top; ++i) {
		x=sta[i]; y=bel[x];
		if (deg[fa[x]]==1) f[x]=f[fa[x]]+1;
		if (y) f[x]=min(f[x], f[y]+dis[y]-dis[x]-1ll*(dep[x]-dep[y])*cnt[x]);
	}
	// cout<<"id : "; for (int i=1; i<=n; ++i) cout<<setw(2)<<i<<' '; cout<<endl;
	// cout<<"bel: "; for (int i=1; i<=n; ++i) cout<<setw(2)<<bel[i]<<' '; cout<<endl;
	// cout<<"f  : "; for (int i=1; i<=n; ++i) cout<<setw(2)<<f[i]<<' '; cout<<endl;
	for (int i=1; i<=n; ++i) if (head[i]==-1) ans=min(ans, f[i]);
	// for (int i=1; i<=n; ++i) if (dep[i]==n-1) ans=min(ans, (ll)dep[i]);
	printf("%lld\n", ans); 

	return 0;
}
posted @ 2022-06-22 22:07  Administrator-09  阅读(3)  评论(0编辑  收藏  举报