bzoj 4477: [Jsoi2015]字符串树

原创 2016年06月01日 16:37:04

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4477

题意

在一棵树上的每条路都有一个字符串,有q个询问(u,v,S),u,v表示树上的两个节点,S表示一个字符串,求u到v路径上字符串中前缀是S的个数。

题解

将树路径上的字符串压缩到作为子节点的点中,之后用树链剖分维护一个可持久化trie树即可,时间复杂度为O(10qlogn)

code
#include <bits/stdc++.h>

#define N 100010

using namespace std;

char str[N][15];

int n, q, tot, QT;
int head[N];
int size[N], dfn[N], fa[N], top[N], son[N], w[N], ran[N];

struct ss
{
    int next, to;
    char ch[15];
};
ss Edge[N << 1];

void add(int x, int y, char *ch)
{
    Edge[++tot].next = head[x], Edge[tot].to = y;
    memcpy(Edge[tot].ch + 1, ch + 1, sizeof(char) * strlen(ch + 1));
    head[x] = tot;
}

namespace trie
{
    int cnt = 1;
    int sum[N * 10], son[N * 10][27], root[N];

    int Insert(int x, char *ch)
    {
        int tmp = ++cnt, y = cnt, len = strlen(ch + 1);
        for(int i = 1; i <= len; i++)
        {
            int p = ch[i] - 'a' + 1;
            for(int j = 0; j <= 26; j++)
                son[y][j] = son[x][j];
            sum[y] = sum[x] + 1, son[y][p] = ++cnt;
            x = son[x][p], y = son[y][p];
        }
        sum[y] = sum[x] + 1;
        return tmp;
    }

    int query(int l, int r, char *ch)
    {
        int x = root[l - 1], y = root[r], len = strlen(ch + 1);
        for(int i = 1; i <= len; i++)
        {
            int p = ch[i] - 'a' + 1;
            x = son[x][p], y = son[y][p];
        }
        return sum[y] - sum[x];
    }

    void build()
    {
        for(int i = 2; i <= n; i++)
            root[i] = Insert(root[i - 1], str[ran[i]]);
    }
}

void dfs(int u, int rt, int deep)
{
    size[u] = 1, fa[u] = rt, dfn[u] = deep;
    for(int i = head[u]; i; i = Edge[i].next)
    {
        int to = Edge[i].to;
        if(to == rt) continue;
        memcpy(str[to] + 1, Edge[i].ch + 1, sizeof(char) * strlen(Edge[i].ch + 1));
        dfs(to, u, deep + 1);
        size[u] += size[to];
        if(size[to] > size[son[u]]) son[u] = to;
    }
}

void dfs(int u, int tp)
{
    top[u] = tp, w[u] = ++QT, ran[QT] = u;
    if(!son[u]) return ;
    dfs(son[u], tp);
    for(int i = head[u]; i; i = Edge[i].next)
    {
        int to = Edge[i].to;
        if(to == fa[u] || to == son[u]) continue;
        dfs(to, to);
    }
}

int ask(int x, int y, char *ch)
{
    int ans = 0;
    while(top[x] != top[y])
    {
        if(dfn[top[x]] < dfn[top[y]]) swap(x, y);
        ans += trie::query(w[top[x]], w[x], ch);
        x = fa[top[x]];
    }
    if(dfn[x] > dfn[y]) swap(x, y);
    ans += trie::query(w[x] + 1, w[y], ch);
    return ans;
}

int main()
{
//  freopen("tt.in", "r", stdin);
    cin >> n;
    for(int x, y, i = 1; i < n; i++)
    {
        char ch[15];
        memset(ch, 0, sizeof(ch));
        scanf("%d%d%s", &x, &y, ch + 1);
        add(x, y, ch), add(y, x, ch);
    }
    dfs(1, 0, 1), dfs(1, 1);
    trie::build();
    cin >> q;
    for(int x, y, i = 1; i <= q; i++)
    {
        char ch[15];
        memset(ch, 0, sizeof(ch));
        scanf("%d%d%s", &x, &y, ch + 1);
        printf("%d\n", ask(x, y, ch));
    }
    return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

bzoj 4477: [Jsoi2015]字符串树 可持久化线段树

题意给出一棵树,每条边上都有一个长度不超过10的字符串。给出m个询问x y ch,求x到y的路径有多少个字符串的前缀是ch。 n,m...

【JSOI2015】字符串树 可持久Tire

题目描述 【故事背景】   萌萌买了一颗字符串树的种子,春天种下去以后夏天就能长出一棵很大的字符串树。字符串树很奇特,树枝上都密密麻麻写满了字符串,看上去很复杂的样子。 【问题描述】 ...

【JZOJ4061】【JSOI2015】字符串树

DescriptionData ConstraintSolution这种题我们考虑什么用打棵字典树和lca来解决。我们对于一个点i,存储从i到根节点路径上的所有字符串,这可以用类似主席树的方法来解决。...

JZOJ 4061. 【JSOI2015】字符串树

DescriptionInputOutputSample Input4 1 2 ab 2 4 ac 1 3 bc 3 1 4 a 3 4 b 3 2 abSample Output2 ...

[JSOI2015][JZOJ4061]字符串树

题目大意一棵有nn个节点的树,每条边有一个长度ll不大于1010的字符串。有qq个询问,形如(x,y,s)(x,y,s)的询问,查询点xx到点yy的路径上,前缀为ss的边的数量。 1≤n,q≤100...

bzoj 4487: [Jsoi2015]染色问题 (容斥原理+组合数学)

题目描述传送门题目大意:棋盘是一个n×m的矩形,分成n行m列共n*m个小方格。现在萌萌和南南有C种不同颜色的颜料,他们希望把棋盘用这些颜料染色,并满足以下规定: 1. 棋盘的每一个小方格既可以染...

BZOJ 4481 [Jsoi2015] 非诚勿扰

期望+树状数组

bzoj 4476: [Jsoi2015]送礼物 二分答案+单调队列

题意给出n,k,l,r和序列a,要求从a中选一段连续的区间[i,j]出来,使得M(i,j)-m(i,j)/(j-i+k)最大。 M(i,j)表示[i,j]中的最大值,m(i,j)表示[i,j]中的最...

bzoj 4474: [Jsoi2015]isomorphism

Description 一个无向树的度数为 2的结点称为假结点,其它结点称为真结点。一个无向树的简化树 其结点由原树的全体真结点组成,两个真结点之间有边当且仅当它们在原树中有边,或者在 原树...
  • lqybzx
  • lqybzx
  • 2016年04月04日 19:13
  • 435

BZOJ 4487 [Jsoi2015] 染色问题

思路+数论
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:bzoj 4477: [Jsoi2015]字符串树
举报原因:
原因补充:

(最多只允许输入30个字)