Codeforces Gym 100962 J. Jimi Hendrix

41 篇文章 0 订阅
2 篇文章 0 订阅

Description

You are given a tree T consisting of n vertices and n1 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 ( 2n5×105,1mn1 ),
the number of vertices in the tree and the length of the string s.
The following n1 lines contain triples ui,vi,ci ( 1ui,vin,uivi,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");
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值