Description
You are given a tree T consisting of n vertices and
n−1
edges. Each edge of the tree is associated
with a lowercase English letter
ci
.
You are given a string s consisting of lowercase English letters. Your task is to nd a simple path
in the tree such that the string formed by concatenation of letters associated with edges of this
path contains string s as a subsequence, or determine that there exists no such simple path.
Input
The rst line of input contains two positive integers n and m (
2≤n≤5×105,1≤m≤n−1
),
the number of vertices in the tree and the length of the string s.
The following
n−1
lines contain triples
ui,vi,ci
(
1≤ui,vi≤n,ui≠vi,ci
is a lowercase English
letter), denoting an edge
(ui,vi)
associated with letter
ci
.
The last line contains a string s (
∣s∣=m
) consisting of lowercase English letters.
Output
If the desired path exists, output its endpoints a and b. Otherwise, output -1 -1
. If there are
several possible answers, you are allowed to output any of them.
题意
给定 G = (V, E) , |E| = |V|-1 的树。树上直接相连两点间的边上记录一个字符
ci
。树上 a 点到 b 点的路径经过的边构成一个字符串,假设为 T 。问给定一个长为 m 的字符串 S ,S 能否成为某个 T 的子序列,如果可以,给出构成 T 串的两个端点 a b
。否则输出 -1 -1
。
分析
貌似已经搞不清此题的算法,感觉算是树分治的问题,但又有最优化问题的思想。
此题的关键在于维护以某点为根的子树的最优状态。
dp[i].lenl
表示以点 i 为根的子树最长已经匹配了 S 串的串首 lenl 个元素,同时匹配这 lenl 个元素的起始点为 idxl 。
dp[i].lenr
表示以点 i 为根的子树最长已经匹配了 S 串的串尾 lenr 个元素,同时匹配这 lenr 个元素的结束点为 idxr 。
任意取一个点作为树的根,跑一遍 dfs 。若在某点最终 dp[i].lenl + dp[i].lenr >= m 且取到这么多元素不止点 i 的同一子树内,则有解。
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e5 + 10;
int n, m;
char ch, s[maxn];
vector< pair<int, char> > g[maxn];
struct Node{
int lenl, lenr, idxl, idxr;
}dp[maxn];
bool dfs(int rt, int fa)
{
for(int i=0, to;i<g[rt].size();i++)
{
to = g[rt][i].first;
if(to == fa) continue;
if(dfs(to, rt)) return true;
int tmpl = s[ dp[to].lenl + 1 ] == g[rt][i].second ? dp[to].lenl+1 : dp[to].lenl;
int tmpr = s[ m - dp[to].lenr ] == g[rt][i].second ? dp[to].lenr+1 : dp[to].lenr;
if(tmpl + dp[rt].lenr >= m) {
printf("%d %d",dp[to].idxl, dp[rt].idxr);
return true;
}
if(tmpr + dp[rt].lenl >= m) {
printf("%d %d",dp[rt].idxl, dp[to].idxr);
return true;
}
if(tmpl > dp[rt].lenl) {
dp[rt].lenl = tmpl;
dp[rt].idxl = dp[to].idxl;
}
if(tmpr > dp[rt].lenr) {
dp[rt].lenr = tmpr;
dp[rt].idxr = dp[to].idxr;
}
}
return false;
}
int main()
{
scanf("%d %d",&n,&m);
for(int i=1, u, v;i<n;i++)
{
scanf("%d %d %c",&u,&v,&ch);
dp[i].lenl = dp[i].lenr = 0;
dp[i].idxl = dp[i].idxr = i;
g[u].push_back(make_pair(v, ch));
g[v].push_back(make_pair(u, ch));
}
dp[n].lenl = dp[n].lenr = 0, dp[n].idxl = dp[n].idxr = n;
scanf(" %s",s+1);
if(!dfs(1, -1)) printf("-1 -1");
}