题解 字符串

传送门

首先题面里那个映射根本没用
暴力可以枚举根然后建出 AC 自动机 check

  • 对大字符集 trie 树建 AC 自动机:考虑用主席树存边,见这里

构造方案考虑 fail 树上与根相邻的点的父边权值两两不同
若 BFS 染色的话下一层的点的父边权值一定与上一层的点的父边权值相等

然后考虑如何少枚举几个点
(并不知如何想到)发现 trie 与 fail 上相同的边一定对应了一些形如 \(\texttt{aaaa...a}\) 的串
只保留这些边,此时度数 \(>2\) 的点为根(空串)
若不存在则保留的边一定是一条链
枚举链上每个点 \(u\),枚举其 trie 上邻居 \(v\),枚举 \(v\) 在 fail 上的邻居 \(k\)
\(k\) 在链上则 \(dis(rot, k)\leqslant 1\)
若不存在则整棵 trie 与 fail 完全相同,任选一点做根均可

点击查看 $O(n^2\log n)$ 代码(雾
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 300010
#define fir first
#define sec second
#define pb push_back
#define ll long long
#define ull unsigned 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;
ull h[N], pw[N];
pair<int, int> bkp[N], bkp2[N];
int val[N], ans[N], back[N], top, btop;
const ull base=13131;
inline ull hashing(int l, int r) {return h[r]-h[l-1]*pw[r-l+1];}
bool have_such_edge(pair<int, int> t);

namespace trie{
	ull th[N];
	map<int, int> to[N];
	int head[N], dep[N], fail2[N], ecnt=1;
	struct edge{int to, next, rk;}e[N<<1];
	inline void add(int s, int t, int id) {e[++ecnt]={t, head[s], id}; head[s]=ecnt;}
	void getdep(int u, int fa) {
		for (int i=head[u],v; ~i; i=e[i].next) {
			v = e[i].to;
			if (v==fa) continue;
			dep[v]=dep[u]+1;
			getdep(v, u);
		}
	}
	bool connect_with_rot(int u) {
		for (int i=head[u],v; ~i; i=e[i].next) {
			v = e[i].to;
			if (!have_such_edge({u, v})) return 0;
		}
		return 1;
	}
	void get_hash(int u, int fa, ull pre) {
		to[u].clear();
		if (fa) th[u]=pre=pre*base+val[u];
		else val[u]=0;
		for (int i=head[u],v; ~i; i=e[i].next) {
			v = e[i].to;
			if (v==fa) continue;
			to[u][val[v]]=v;
			get_hash(v, u, pre);
		}
	}
	bool check_char(int u, int fa) {
		//cout<<"check_char: "<<u<<' '<<fa<<endl;
		if (!fa) top=0;
		else {
			++top; h[top]=h[top-1]*base+val[u];
			int anc=back[u];
			assert(anc);
			int len=dep[anc]-1;
			//cout<<"anc: "<<anc<<endl;
			//cout<<"len: "<<len<<endl;
			//cout<<"hash: "<<hashing(top-len+1, top)<<' '<<th[anc]<<endl;
			if (len && hashing(top-len+1, top)!=th[anc]) return 0;
		}
		for (int i=head[u],v; ~i; i=e[i].next) {
			v = e[i].to;
			if (v==fa) continue;
			if (!check_char(v, u)) return 0;
		}
		--top;
		return 1;
	}
	void init_ans(int u, int in_edge) {
		if (in_edge) ans[e[in_edge].rk]=val[u];
		for (int i=head[u],v; ~i; i=e[i].next) {
			v = e[i].to;
			if (i==(in_edge^1)) continue;
			init_ans(v, i);
		}
	}
	bool recheck(int rot) {
		memset(fail2, 0, sizeof(fail2));
		queue<int> q;
		for (auto v:to[rot]) q.push(v.sec), fail2[v.sec]=rot;
		while (q.size()) {
			int u=q.front(); q.pop();
			for (auto v:to[u]) {
				q.push(v.sec);
				int now=fail2[u];
				while (now!=rot && to[now].find(v.fir)==to[now].end()) now=fail2[now];
				if (to[now].find(v.fir)!=to[now].end()) fail2[v.sec]=to[now][v.fir];
				else fail2[v.sec]=rot;
			}
		}
		//cout<<"fail2: "; for (int i=1; i<=n; ++i) cout<<fail2[i]<<' '; cout<<endl;
		for (int i=1; i<=n; ++i) if (i!=rot && !have_such_edge({fail2[i], i})) return 0;
		return 1;
	}
}

namespace fail{
	int head[N], ecnt;
	map<pair<int, int>, bool> mp;
	struct edge{int to, next;}e[N<<1];
	inline void add(int s, int t) {mp[{s, t}]=mp[{t, s}]=1; e[++ecnt]={t, head[s]}; head[s]=ecnt;}
	bool is_able_dep(int u, int fa) {
		for (int i=head[u],v; ~i; i=e[i].next) {
			v = e[i].to;
			if (v==fa) continue;
			if (trie::dep[v]<=trie::dep[u]) return 0;
			if (!is_able_dep(v, u)) return 0;
		}
		return 1;
	}
	bool have_such_edge(pair<int, int> t) {return mp.find(t)!=mp.end();}
	void spread_char(int u, int fa, int col) {
		val[u]=col;
		for (int i=head[u],v; ~i; i=e[i].next) {
			v = e[i].to;
			if (v==fa) continue;
			back[v]=u;
			spread_char(v, u, col);
		}
	}
	void set_char(int u) {
		int now=0; val[u]=0;
		for (int i=head[u],v; ~i; i=e[i].next) {
			v = e[i].to;
			back[v]=u;
			spread_char(v, u, ++now);
		}
	}
}
bool have_such_edge(pair<int, int> t) {return fail::mp.find(t)!=fail::mp.end();}

namespace task1{
	void solve() {
		for (int i=1; i<=n; ++i) {
			//cout<<"i: "<<i<<endl;
			trie::dep[i]=1; trie::getdep(i, 0);
			//cout<<"dep: "; for (int i=1; i<=n; ++i) cout<<trie::dep[i]<<' '; cout<<endl;
			if (!fail::is_able_dep(i, 0)) continue;
			if (!trie::connect_with_rot(i)) continue;
			//cout<<"live"<<endl;
			fail::set_char(i);
			//cout<<"val: "; for (int i=1; i<=n; ++i) cout<<val[i]<<' '; cout<<endl;
			trie::get_hash(i, 0, 0);
			//cout<<"th: "; for (int i=1; i<=n; ++i) cout<<trie::th[i]<<' '; cout<<endl;
			if (trie::check_char(i, 0)) {
				trie::init_ans(i, 0);
				printf("%d\n", i);
				for (int j=1; j<n; ++j) printf("%d ", ans[j]);
				printf("\n");
				exit(0);
			}
		}
		assert(0);
	}
}

namespace task2{
	int cnt[N];
	vector<int> tem;
	void solve() {
		for (int i=1; i<n; ++i) if (have_such_edge(bkp2[i])) bkp[++btop]=bkp2[i];
		for (int i=1; i<=btop; ++i) ++cnt[bkp[i].fir], ++cnt[bkp[i].sec];
		//cout<<"cnt: "; for (int i=1; i<=n; ++i) cout<<cnt[i]<<' '; cout<<endl;
		for (int i=1; i<=n; ++i) if (cnt[i]>2) {tem.pb(i); goto jump;}
		for (int i=1; i<=n; ++i) if (cnt[i]) {
			for (int j=trie::head[i],v; ~j; j=trie::e[j].next) {
				v = trie::e[j].to;
				if (cnt[v]) continue;
				for (int k=fail::head[v],t; ~k; k=fail::e[k].next) {
					t = fail::e[k].to;
					if (cnt[t]) tem.pb(t);
				}
			}
		}
		assert(tem.size()<=3);
		if (!tem.size()) tem.pb(1);
		for (int i=1; i<=btop; ++i) if (
		//cout<<"tem: "; for (auto it:tem) cout<<it<<' '; cout<<endl;
		sort(tem.begin(), tem.end());
		tem.erase(unique(tem.begin(), tem.end()), tem.end());
		//cout<<"tem: "; for (auto it:tem) cout<<it<<' '; cout<<endl;
		jump:
		for (auto i:tem) {
			///cout<<"i: "<<i<<endl;
			trie::dep[i]=1; trie::getdep(i, 0);
			if (!fail::is_able_dep(i, 0)) continue;
			if (!trie::connect_with_rot(i)) continue;
			fail::set_char(i);
			trie::get_hash(i, 0, 0);
			if (trie::check_char(i, 0)&&trie::recheck(i)) {
				trie::init_ans(i, 0);
				printf("%d\n", i);
				for (int j=1; j<n; ++j) printf("%d ", ans[j]);
				printf("\n");
				exit(0);
			}
		}
		assert(0);
	}
}

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

	n=read();
	memset(trie::head, -1, sizeof(trie::head));
	memset(fail::head, -1, sizeof(fail::head));
	for (int i=1,u,v; i<n; ++i) {
		u=read(); v=read();
		trie::add(u, v, i); trie::add(v, u, i);
		bkp2[i]={u, v};
	}
	for (int i=1,u,v; i<n; ++i) {
		u=read(); v=read();
		fail::add(u, v); fail::add(v, u);
	}
	pw[0]=1;
	for (int i=1; i<=n; ++i) pw[i]=pw[i-1]*base;
	task2::solve();
	
	return 0;
}
posted @ 2022-02-21 19:14  Administrator-09  阅读(1)  评论(0编辑  收藏  举报