HDU 5790 Prefix(字典树+主席树)

Prefix

Time Limit: 2000/4000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 858    Accepted Submission(s): 256

Problem Description

Alice gets N strings. Now she has Q questions to ask you. For each question, she wanna know how many different prefix strings between Lth and Rth strings. It‘s so easy right? So solve it!

Input

The input contains multiple test cases.

For each test case, the first line contains one integer N(1≤N≤100000). Then next N lines contain N strings and the total length of N strings is between 1 and 100000. The next line contains one integer Q(1≤Q≤100000). We define a specail integer Z=0. For each query, you get two integer L, R(0=<L,R<N). Then the query interval [L,R] is [min((Z+L)%N,(Z+R)%N)+1,max((Z+L)%N,(Z+R)%N)+1]. And Z change to the answer of this query.

Output

For each question, output the answer.

Sample Input

3

abc

aba

baa

3

0 2

0 1

1 1

Sample Output

7

6

3

题目链接:HDU 5790

就是问你[L,R]中的字符串的前缀一共有多少种,那么我们可以把每一个字符串的前缀标号,然后记录这种字符串有几种前缀并更新到主席树上,每一次问[L,R]就变成询问[presum_kind[L-1]+1, presum_kind[R]]之间有几个不同的前缀标号,比如题目样例给前缀标号,就是[1,2,3][1,2,4][5,6,7]。

代码:

#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define LC(ql) (ql<<1)
#define RC(ql) ((ql<<1)+1)
#define MID(ql,qr) ((ql+qr)>>1)
#define fin(name) freopen(name,"r",stdin)
#define fout(name) freopen(name,"w",stdout)
#define CLR(arr,val) memset(arr,val,sizeof(arr))
#define FAST_IO ios::sync_with_stdio(false);cin.tie(0);
typedef pair<int, int> pii;
typedef long long LL;
const double PI = acos(-1.0);
const int N = 100010;
struct Trie
{
    int nxt[26];
    int id;
    void reset()
    {
        fill(nxt, nxt + 26, 0);
        id = 0;
    }
};
struct seg
{
    int lson, rson;
    int cnt;
    void reset()
    {
        lson = rson = 0;
        cnt = 0;
    }
};
Trie L[N];
seg T[N * 36];
int sz, tot, tid, arr[N], Tot;
int lenth[N], last[N], root[N];
char s[N];

void init()
{
    sz = 1;
    tot = 0;
    tid = 0;
    Tot = 0;
    CLR(last, 0);
    L[0].reset();
}
void update(int &cur, int ori, int l, int r, int pos, int flag)
{
    cur = ++tot;
    T[cur] = T[ori];
    T[cur].cnt += flag;
    if (l == r)
        return ;
    int mid = MID(l, r);
    if (pos <= mid)
        update(T[cur].lson, T[ori].lson, l, mid, pos, flag);
    else
        update(T[cur].rson, T[ori].rson, mid + 1, r, pos, flag);
}
int query(int S, int E, int l, int r, int ql, int qr)
{
    if (ql <= l && r <= qr)
        return T[E].cnt - T[S].cnt;
    else
    {
        int ret = 0;
        int mid = MID(l, r);
        if (ql <= mid)
            ret += query(T[S].lson, T[E].lson, l, mid, ql, qr);
        if (qr > mid)
            ret += query(T[S].rson, T[E].rson, mid + 1, r, ql, qr);
        return ret;
    }
}
int insert(int id, char s[])
{
    int len = strlen(s);
    int u = 0;
    for (int i = 0; i < len; ++i)
    {
        int v = s[i] - ‘a‘;
        if (!L[u].nxt[v])
        {
            L[sz].reset();
            L[u].nxt[v] = sz++;
        }
        u = L[u].nxt[v];
        if (L[u].id == 0)
            L[u].id = ++tid;
        arr[++Tot] = L[u].id;
    }
    lenth[id] = Tot;
    return len;
}
int main(void)
{
    int n, m, i, l, r;
    while (~scanf("%d%d", &n, &m))
    {
        init();
        for (i = 0; i < n; ++i)
        {
            scanf("%s", s);
            insert(i, s);
        }
        for (i = 1; i <= Tot; ++i)
        {
            if (!last[arr[i]])
                update(root[i], root[i - 1], 1, Tot, i, 1);
            else
            {
                int tmp;
                update(tmp, root[i - 1], 1, Tot, last[arr[i]], -1);
                update(root[i], tmp, 1, Tot, i, 1);
            }
            last[arr[i]] = i;
        }
        scanf("%d", &m);
        int ans = 0;
        while (m--)
        {
            int L, R;
            scanf("%d%d", &L, &R);
            l = min((L + ans) % n, (R + ans) % n);
            r = max((L + ans) % n, (R + ans) % n);
            L = l - 1 >= 0 ? lenth[l - 1] : 0;
            R = lenth[r];
            printf("%d\n", ans = query(root[L], root[R], 1, Tot, L + 1, R));
        }
    }
    return 0;
}
时间: 2024-10-12 15:30:06

HDU 5790 Prefix(字典树+主席树)的相关文章

HDU 4866 多校1 主席树+扫描线

终于是解决了这个题目了 不过不知道下一次碰到主席树到底做不做的出来,这个东西稍微难一点就不一定能做得出 离散化+扫描线式的建树,所以对于某个坐标二分找到对应的那颗主席树,即搜索出结果即可(因为是扫描线式的建树,找到对应的树之后,就知道该点上面的线段有多少条了) 其他就是普通主席树的操作了 主席树里面维护两个东西,一个就是普通的那种在该区间的节点数目,另外就是权值 #include <iostream> #include <cstdio> #include <cstring&g

hdu 2665 可持久化线段树求区间第K大值(函数式线段树||主席树)

http://acm.hdu.edu.cn/showproblem.php?pid=2665 Problem Description Give you a sequence and ask you the kth big number of a inteval. Input The first line is the number of the test cases. For each test case, the first line contain two integer n and m (

可持久化线段树--主席树

浅谈可持久化线段树--主席树 权值线段树 权值线段树和普通线段树不一样的地方就是在于 它的结点存储的是区间内数的个数 这个线段树的好处就在于我们可以根据 左子树 和 右子树 的大小从而进行 查找某个数的排名 或者 查找排名为rk的数 可持久化的含义 可持久数据结构主要指的是我们可以查询历史版本的情况并支持插入,利用使用之前历史版本的数据结构来减少对空间的消耗(能够对历史进行修改的是函数式). 主席树的建树过程: 最开始的时候就是一个空树 然后我们再插入一个元素3 再加入一个元素 1 模版一 :求

hdu 4348 To the moon(主席树区间操作)

题目链接:hdu 4348 To the moon 题意: 给你n个数,有m个操作. 1.给区间[l,r]的所有数+d,并且时间戳+1 2.询问当前时间戳的区间和. 3.询问过去时间戳t的区间和. 4.退回到时间戳t. 题解: 直接上主席树. 不过区间操作的时候push_down空间似乎不是那么够用. 所有把push_down这个操作去掉. 用一个标记记录当前这个区间的累加. 询问的时候就将这个累加传下去.(具体看代码) 最后还有退回状态t的时候可以把cnt=root[t+1], 因为后面的内存

HDU 4417 Super Mario(主席树求区间内的区间查询+离散化)

Super Mario Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 5101    Accepted Submission(s): 2339 Problem Description Mario is world-famous plumber. His “burly” figure and amazing jumping abilit

POJ 2104&amp;HDU 2665 Kth number(主席树入门+离散化)

K-th Number Time Limit: 20000MS   Memory Limit: 65536K Total Submissions: 50247   Accepted: 17101 Case Time Limit: 2000MS Description You are working for Macrohard company in data structures department. After failing your previous task about key inse

hdu 4348 To the moon (主席树)

hdu 4348 题意: 一个长度为n的数组,4种操作 : (1)C l r d:区间[l,r]中的数都加1,同时当前的时间戳加1 . (2)Q l r:查询当前时间戳区间[l,r]中所有数的和 . (3)H l r t:查询时间戳t区间[l,r]的和 . (4)B t:将当前时间戳置为t . 所有操作均合法 . 解法: 很明显是一道主席树的题 . 对于每一次区间加法都新建节点建一棵线段树,加个懒惰标记就行了,查询的话直接线段树区间求和 . 不过感觉这一题就是为可持续化数据结构写的,特别是时间戳

hdu 4417 Super Mario (主席树)

链接:http://acm.hdu.edu.cn/showproblem.php?pid=4417 题意: 给你段长为n的序列,有q个询问,每次询问区间[l.r]内有多少个数小于等于k 思路: 之前用分块写过类似的,不过为了练习下主席树,这里用主席树写了下.思路很简单 离线离散化处理下,每次插入一个数num时,在主席树上下标num+1,这样每次询问[l,r]中有多少个小于k的数的时候,我们只要找下标[1,k]的区间第R次修改后的总和减去第L-1次修改后的总值就可以得到了 实现代码: #inclu

HDU 5919 -- Sequence II (主席树)

题意: 给一串数字,每个数字的位置是这个数第一次出现的位置. 每个询问对于序列的一个子区间,设一共有k个不同的数,求第ceil(k/2)个数的位置. 因为强制在线,所以离线乱搞pass掉. 主席树可解. 考虑一个数列: p      1 2 3 4 5 6  // 原序列标号 a : 1 2 1 2 3 4  // 原序列 p1 1 2 1 2 5 6  // 子序列开始下标为1 p2        2 3 1 5 6 p3           3 4 5 6 p4              4