[Jsoi2015]字符串树 hash+主席树+LCA

标签: hash 主席树 LCA
8人阅读 评论(0) 收藏 举报
分类:

Description
字符串树本质上还是一棵树,即N个节点N-1条边的连通无向无环图,节点从1到N编号。与普通的树不同的是,树上的每条边都对应了一个字符串。每次给出一个字符串S和两个节点U,V,需要回答U和V之间上有多少个字符串以S为前缀。


Sample Input
4
1 2 ab
2 4 ac
1 3 bc
3
1 4 a
3 4 b
3 2 ab


Sample Output
2
1
1


这道题由于它字符串长度小于10,那你就对它的所有前缀的hash暴力建树,然后像COT那样做就好了,不过我的代码好像不太优秀,OJ时间复杂度倒数Rank1。。。


#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
typedef unsigned long long ULL;
int read() {
    int x = 0, f = 1;char ch = getchar();
    while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
    while(ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
    return x * f;
}
const int hs = 29;
const ULL inf = 18446744073709551615UL;

struct edge {
    int x, y, next, o;
    ULL ss[11];
} e[210000]; int len, last[110000];
struct node {
    int lc, rc, c;
} t[31000000]; int cnt, rt[210000];
ULL A[11]; int fa[110000][21], dep[110000];
char ss[11];

void ins(int x, int y, int kk) {
    e[++len].x = x; e[len].y = y; e[len].o = kk;
    for(int i = 1; i <= kk; i++) e[len].ss[i] = A[i];
    e[len].next = last[x]; last[x] = len;
}

void Link(int &u, ULL l, ULL r, ULL p) {
    if(!u) u = ++cnt;
    t[u].c++;
    if(l == r) return ;
    ULL mid = l / 2 + r / 2;
    if(p <= mid) Link(t[u].lc, l, mid, p);
    else Link(t[u].rc, mid + 1, r, p);
}

void Merge(int &u1, int u2) {
    if(!u1 || !u2) {u1 = u1 + u2; return ;}
    t[u1].c += t[u2].c;
    Merge(t[u1].lc, t[u2].lc);
    Merge(t[u1].rc, t[u2].rc);
}

int query(int u1, int u2, int u3, ULL l, ULL r, ULL k) {
    if(l == r) return t[u1].c + t[u2].c - t[u3].c * 2;
    ULL mid = l / 2 + r / 2;
    if(k <= mid) return query(t[u1].lc, t[u2].lc, t[u3].lc, l, mid, k);
    else return query(t[u1].rc, t[u2].rc, t[u3].rc, mid + 1, r, k);
}

void dfs(int x) {
    for(int i = 1; i <= 18; i++) fa[x][i] = fa[fa[x][i - 1]][i - 1];
    for(int k = last[x]; k; k = e[k].next) {
        int y = e[k].y;
        if(y != fa[x][0]) {
            for(int i = 1; i <= e[k].o; i++) Link(rt[y], 0, inf, e[k].ss[i]);
            Merge(rt[y], rt[x]);
            fa[y][0] = x; dep[y] = dep[x] + 1;
            dfs(y);
        }
    }
}

int LCA(int x, int y) {
    if(dep[x] < dep[y]) swap(x, y);
    for(int i = 18; i >= 0; i--) {
        if(dep[x] - dep[y] >= (1 << i)) {
            x = fa[x][i];
        }
    }
    if(x == y) return x;
    for(int i = 18; i >= 0; i--) {
        if(fa[x][i] != fa[y][i]) {
            x = fa[x][i], y = fa[y][i];
        }
    }
    return fa[x][0];
}

int main() {
    int n = read();
    for(int i = 1; i < n; i++) {
        int x = read(), y = read();
        scanf("%s", ss + 1); int u = strlen(ss + 1);
        for(int i = 1; i <= u; i++) A[i] = A[i - 1] * hs + ss[i] - 'a' + 1;
        ins(x, y, u); ins(y, x, u);
    }
    dfs(1);
    int m = read();
    for(int i = 1; i <= m; i++) {
        int x = read(), y = read(); scanf("%s", ss + 1);
        ULL cc = 0;
        for(int i = 1; i <= strlen(ss + 1); i++) cc = cc * hs + ss[i] - 'a' + 1;
        int lca = LCA(x, y);
        printf("%d\n", query(rt[x], rt[y], rt[lca], 0, inf, cc));
    }
    return 0;
}
查看评论

【JZOJ4061】【JSOI2015】字符串树

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

【JSOI2015】字符串树

分析这题,我们可以建一棵字典树,对于每个询问(x,y),字符s。我们先算出从根到x中的s出现的次数dat1,然后再计算起点到y中的s出现的次数dat2,再算从起点到lca(x,y)的s出现的次数dat...
  • xieguofu2014
  • xieguofu2014
  • 2016年01月28日 20:16
  • 954

[BZOJ4539][Hnoi2016]树(倍增+LCA+主席树)

这篇题解ATP竟然码了三天。。
  • FromATP
  • FromATP
  • 2017年02月16日 21:04
  • 534

【JSOI2015】字符串树 可持久Tire

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

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 ...
  • liyizhixl
  • liyizhixl
  • 2017年02月11日 20:57
  • 220

[BZOJ4477][JSOI2015]字符串树 可持久化Trie树

首先考虑树上差分,xx到yy的答案可以差分成xx到根+yy到根-2∗lca(x,y)2*lca(x,y)到根的答案。 考虑如何维护每个点到根路径上的所有字符串,想到Trie树,又因为每个点和其父亲只...
  • DOFYPXY
  • DOFYPXY
  • 2017年12月18日 22:20
  • 122

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

题意给出一棵树,每条边上都有一个长度不超过10的字符串。给出m个询问x y ch,求x到y的路径有多少个字符串的前缀是ch。 n,m...
  • qq_33229466
  • qq_33229466
  • 2017年03月09日 15:34
  • 342

JSOI2015

[BZOJ4475] [Jsoi2015]子集选取 题目大意 定义全集为{1,2,⋯,n}\{1,2,\cdots,n\},要求构成一个m*m的三角形,使得三角形(i,j)(i,j)所代表的集合是(...
  • slongle_amazing
  • slongle_amazing
  • 2016年04月06日 10:36
  • 1127

[JSOI2015][JZOJ4061]字符串树

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

bzoj4477 [Jsoi2015]字符串树

Description 萌萌买了一颗字符串树的种子,春天种下去以后夏天就能长出一棵很大的字 符串树。字符串树很奇特,树枝上都密密麻麻写满了字符串,看上去很复杂的样 子。 问题描述 字...
  • jpwang8
  • jpwang8
  • 2018年03月07日 17:28
  • 24
    个人资料
    持之以恒
    等级:
    访问量: 8578
    积分: 651
    排名: 7万+
    文章存档
    最新评论