题解 排序

传送门

首先有一个暴力是在每个节点维护所有可能的上升序列,用一个区间表示
发现有包含关系的区间中主动包含的那个一定不优,剪掉即可
发现合并时的 \(O(k!)\) 合并可以用状压,按照加入顺序 DP 优化
\(f[s]\) 表示已选的儿子为 \(s\) 时的又端点最小值)
发现如果当前节点只有一个儿子,信息是可以 \(O(1)\) 继承的

好的现在我们来证明这个东西的复杂度是对的(((
大意是将原树按每个子树包含的 \(\sum m_i\) 数量轻重链剖分
考虑每个节点的合法线段数量
发现每条合法线段的两个端点中至少有一个不属于重儿子
发现任意一个可能作为端点的点最多只能作为一个合法区间的端点
所以合法线段数量不超过 \(\sum m_u-\sum m_{mson_u}\)
也就是每个叶子上的数字只在向上跳到链顶时产生一次贡献
那么总贡献是 \(O(n \log n)\) 级别的
所以总复杂度是(\(\sum m_i\)\(n\) 同级) \(O(k2^{k-1}n \log n+n \log^2 n)\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define fir first
#define sec second
#define pb push_back
#define ll long long
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n;
bool leaf[N];
vector<int> buc[N];
int head[N], sta[N], deg[N], top, ecnt;
struct edge{int to, next;}e[N<<1];
inline void add(int s, int t) {e[++ecnt]={t, head[s]}; head[s]=ecnt;}

#if 0
namespace force{
	int val[N];
	vector<int> rec[N];
	vector<int> dfs1(int u) {
		int tot=0;
		vector<int> now, son[8], id;
		rec[u].clear();
		if (leaf[u]) {now.pb(val[u]); return now;}
		for (auto v:e[u]) {
			son[tot++]=dfs1(v);
			rec[u].pb(tot-1);
			id.pb(v);
		}
		sort(rec[u].begin(), rec[u].end(), [&](int a, int b){return son[a][0]<son[b][0];});
		for (auto it:rec[u]) {for (auto t:son[it]) now.pb(t);}
		for (int i=0; i<rec[u].size(); ++i) rec[u][i]=id[rec[u][i]];
		return now;
	}
	void check() {
		vector<int> t=dfs1(1);
		int lst=0;
		for (auto it:t) {
			if (it<=lst) return ;
			lst=it;
		}
		puts("Yes");
		for (int i=1; i<=n; ++i)
			if (leaf[i]) printf("%d\n", val[i]);
			else {for (auto it:rec[i]) printf("%d ", it); printf("\n");}
		exit(0);
	}
	void dfs2(int u) {
		if (u>top) {check(); return ;}
		for (auto it:buc[sta[u]]) {
			val[sta[u]]=it;
			dfs2(u+1);
		}
	}
	void solve() {
		dfs2(1);
		puts("No");
		exit(0);
	}
}
#endif

namespace task{
	int f[1<<8];
	vector<int> ans[N];
	vector<pair<int, int>> tem[N], g[1<<8];
	vector<vector<pair<int, int>>> rec[N];
	struct tpl{int l, r, bel, rk;};
	vector<tpl> tp[N];
	inline bool operator < (tpl a, tpl b) {return a.l<b.l;}
	void dfs1(int u) {
		// cout<<"dfs: "<<u<<endl;
		int son[8], tot=0;
		if (leaf[u]) {for (auto it:buc[u]) tem[u].pb({it, it}); sort(tem[u].begin(), tem[u].end()); return ;}
		if (deg[u]==1) {int v=e[head[u]].to; dfs1(v); swap(tem[u], tem[v]); swap(rec[u], rec[v]); return ;}
		for (int i=head[u],v; ~i; i=e[i].next) {
			v = e[i].to;
			dfs1(v);
			son[tot++]=v;
			int cnt=0;
			for (auto it:tem[v]) tp[u].pb({it.fir, it.sec, tot-1, cnt++});
		}
		// cout<<"calc: "<<u<<endl;
		// cout<<"son: "; for (int i=0; i<tot; ++i) cout<<son[i]<<' '; cout<<endl;
		sort(tp[u].begin(), tp[u].end());
		vector<pair<pair<int, int>, vector<pair<int, int>>>> all;
		int lim=1<<tot;
		for (auto it:tp[u]) {
			for (int s=0; s<lim; ++s) if (s&(1<<it.bel)) f[s]=INF, g[s].clear();
			f[1<<it.bel]=it.r; g[1<<it.bel].pb({it.bel, it.rk});
			for (int s=0; s<lim; ++s) if (s&(1<<it.bel)) {
				for (int i=0; i<tot; ++i) if (!(s&(1<<i))) {
					auto t=lower_bound(tem[son[i]].begin(), tem[son[i]].end(), make_pair(f[s], 0));
					if (t==tem[son[i]].end()) continue;
					if (f[s|(1<<i)]>t->sec) {
						f[s|(1<<i)]=t->sec;
						g[s|(1<<i)]=g[s];
						g[s|(1<<i)].pb(make_pair(i, t-tem[son[i]].begin()));
					}
				}
			}
			if (f[lim-1]!=INF) all.pb({{it.l, f[lim-1]}, g[lim-1]});
		}
		sort(all.begin(), all.end());
		int lst=0;
		for (auto it:all) if (it.fir.fir!=lst) {
			lst=it.fir.fir;
			while (tem[u].size() && tem[u].back().sec>=it.fir.sec) tem[u].pop_back(), rec[u].pop_back();
			tem[u].pb(it.fir); rec[u].pb(it.sec);
		}
	}
	void dfs2(int u, int id) {
		int son[8], tot=0;
		if (leaf[u]) {ans[u].pb(tem[u][id].fir); return ;}
		for (int i=head[u],v; ~i; i=e[i].next) {
			v = e[i].to;
			son[tot++]=v;
		}
		if (deg[u]==1) {
			ans[u].pb(son[0]);
			swap(tem[u], tem[son[0]]);
			swap(rec[u], rec[son[0]]);
			dfs2(son[0], id);
			return ;
		}
		for (auto it:rec[u][id]) ans[u].pb(son[it.fir]), dfs2(son[it.fir], it.sec);
	}
	void solve() {
		dfs1(1);
		#if 0
		cout<<"---tem---"<<endl;
		for (int i=1; i<=n; ++i) {for (auto it:tem[i]) cout<<"("<<it.fir<<','<<it.sec<<")"<<' '; cout<<endl;}
		cout<<"---rec---"<<endl;
		for (int i=1; i<=n; ++i) {for (auto v:rec[i]) {cout<<"{"; for (auto it:v) cout<<"("<<it.fir<<','<<it.sec<<")"; cout<<"} ";} cout<<endl;}
		#endif
		if (!tem[1].size()) {puts("No"); exit(0);}
		puts("Yes");
		dfs2(1, 0);
		for (int i=1; i<=n; ++i)
			if (leaf[i]) printf("%d\n", ans[i][0]);
			else {for (auto it:ans[i]) printf("%d ", it); printf("\n");}
	}
}

signed main()
{
	freopen("sort.in", "r", stdin);
	freopen("sort.out", "w", stdout);

	n=read();
	memset(head, -1, sizeof(head));
	for (int i=1,k; i<=n; ++i) {
		if (read()&1) {
			deg[i]=k=read();
			while (k--) add(i, read());
		}
		else {
			leaf[sta[++top]=i]=1;
			k=read();
			while (k--) buc[i].pb(read());
		}
	}
	// if (n<=20) force::solve();
	// else puts("No");
	task::solve();
	
	return 0;
}
posted @ 2022-02-11 10:04  Administrator-09  阅读(0)  评论(0编辑  收藏  举报