题解 字符串
首先题面里那个映射根本没用
暴力可以枚举根然后建出 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;
}