【HUD-5790】Prefix (主席树+tire)

似乎是归队赛的最后一道题。

由于当时以为是公共字串所以没写555555,其实是求公共前缀。

做法是建立tire,把tire上的点编号看成是值,查询第l到第r个字符串的区间内不重复的值的个数。建立主席树维护即可

#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define dow(i,l,r) for(int i=r;i>=l;i--)
#define LL long long
#define maxn 100100
#define mm 100000
#define maxm 8000000
using namespace std;

int lson[maxm],rson[maxm],size[maxm],root[maxn],num[maxn],n,m,toti,totr,tot,son[maxn][26],pre[maxn];
char s[maxn];

int more1()
{
    ++toti;
    memset(son[toti],0,sizeof(son[toti]));
    return toti;
}

int more2()
{
    ++totr;
    lson[totr]=0;
    rson[totr]=0;
    size[totr]=0;
    return totr;
}

void add(int &x,int old,int l,int r,int y,int z)
{
    x=more2();
    lson[x]=lson[old];
    rson[x]=rson[old];
    size[x]=size[old]+z;
    if (l==r) return;
    int mid=(l+r)>>1;
    if (y<=mid) add(lson[x],lson[old],l,mid,y,z);
    else add(rson[x],rson[old],mid+1,r,y,z);
}

int ask(int x,int y,int l,int r)
{
//    printf("%d %d %d %d %d %d %d\n",x,y,l,r,size[x],size[lson[x]],size[rson[x]]);
    if (!x) return 0;
    if (l==r) return size[x];
    int  mid=(l+r)>>1;
    if (y<=mid) return ask(lson[x],y,l,mid)+size[rson[x]];
    return ask(rson[x],y,mid+1,r);
} 

int main()
{
    while (scanf("%d",&n)!=EOF) {
        memset(pre,0,sizeof(pre));
        toti=0;
        more1();
        totr=0;
        tot=1;
        rep(i,1,n) {
            scanf("%s",s);
            int len=strlen(s);
            int u=1;
            root[i]=root[i-1];
            rep(j,0,len-1) {
            //    printf("\t%d\n",u);
                ++tot;
                if (!j) num[i]=tot;
                int k=s[j]-‘a‘;
                if (!son[u][k]) son[u][k]=more1();
            //    printf("\t%d\n",u);
                add(root[i],root[i],1,mm,tot,1);
                if (pre[son[u][k]]) {
        //            printf("\t\t%d\n",pre[son[u][k]]);
                    add(root[i],root[i],1,mm,pre[son[u][k]],-1);
                }
                pre[son[u][k]]=tot;
                u=son[u][k];
        //        printf("\t%d\n",u);
            }
        //    printf("%d\n",size[root[i]]);
        }
        scanf("%d",&m);
        int z=0;
        while (m--) {
            int j,k;
            scanf("%d %d",&j,&k);
            int l=min((j+z)%n+1,(k+z)%n+1),r=max((j+z)%n+1,(k+z)%n+1);
    //        printf("%d %d\n",l,r);
            printf("%d\n",z=ask(root[r],num[l],1,mm));
        }
    }
    return 0;
}
 

时间: 2024-10-01 03:24:10

【HUD-5790】Prefix (主席树+tire)的相关文章

SPOJ 10628 Count on a tree(Tarjan离线LCA+主席树求树上第K小)

COT - Count on a tree #tree You are given a tree with N nodes.The tree nodes are numbered from 1 to N.Each node has an integer weight. We will ask you to perform the following operation: u v k : ask for the kth minimum weight on the path from node u 

[poj2104]可持久化线段树入门题(主席树)

解题关键:离线求区间第k小,主席树的经典裸题: 对主席树的理解:主席树维护的是一段序列中某个数字出现的次数,所以需要预先离散化,最好使用vector的erase和unique函数,很方便:如果求整段序列的第k小,我们会想到离散化二分和线段树的做法, 而主席树只是保存了序列的前缀和,排序之后,对序列的前缀分别做线段树,具有差分的性质,因此可以求任意区间的第k小,如果主席树维护索引,只需要求出某个数字在主席树中的位置,即为sort之后v中的索引:若要求第k大,建树时反向排序即可 1 #include

【BZOJ 3551】[ONTAK2010] Peaks加强版 Kruskal重构树+树上倍增+主席树

这题真刺激...... I.关于Kruskal重构树,我只能开门了,不过补充一下那玩意还是一棵满二叉树.(看一下内容之前请先进门坐一坐) II.原来只是用树上倍增求Lca,但其实树上倍增是一种方法,Lca只是他的一种应用,他可以搞各种树上问题,树上倍增一般都会用到f数组. |||.我们跑出来dfs序就能在他的上面进行主席树了. IV.别忘了离散. V.他可能不连通,我一开始想到了,但是我觉得出题人可能会是好(S)人(B),但是...... #include <cstdio> #include

[bzoj3932][CQOI2015]任务查询系统-题解[主席树][权值线段树]

Description 最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分.超级计算机中的 任务用三元组(Si,Ei,Pi)描述,(Si,Ei,Pi)表示任务从第Si秒开始,在第Ei秒后结束(第Si秒和Ei秒任务也在运行 ),其优先级为Pi.同一时间可能有多个任务同时执行,它们的优先级可能相同,也可能不同.调度系统会经常向 查询系统询问,第Xi秒正在运行的任务中,优先级最小的Ki个任务(即将任务按照优先级从小到大排序后取前Ki个 )的优先级之和是多少.特别的,如

BZOJ_3207_花神的嘲讽计划1_(Hash+主席树)

描述 http://www.lydsy.com/JudgeOnline/problem.php?id=3207 给出一个长度为\(n\)的串,以及\(m\)个长度为\(k\)的串,求每个长度为\(k\)的串在原串\([x,y]\)区间是否出现过. 分析 这道题要求对比长度为\(k\)的串,于是我们把这些串的Hash值都算出来,问题就转化成了求\([x,y]\)的区间中是否出现过某Hash值. 求区间中某一个值出现了多少次,可以用主席树. p.s. 1.学习了主席树指针的写法,比数组慢好多啊...

[主席树]ZOJ3888 Twelves Monkeys

题意:有n年,其中m年可以乘时光机回到过去,q个询问 下面m行,x,y 表示可以在y年穿越回x年, 保证y>x 下面q个询问, 每个询问有个年份k 问的是k年前面 有多少年可以通过一种以上($\ge 2$)方法穿越回去的, 其中时光机只能用一次 比如案例 9 3 3 9 1 6 1 4 1 6 7 2 如图 对于询问 6这一年:1.穿越回第1年  2.等时间过呀过呀过到第9年,再穿越回第1年 那么第1年就有两种方法可以穿越回去, 同理, 2.3.4年也有同样两种方法(回到1再等时间过呀过 过到2

POJ2104主席树模板题

完成新成就——B站上看了算法https://www.bilibili.com/video/av4619406/?from=search&seid=17909472848554781180#page=2 K-th Number Time Limit: 20000MS   Memory Limit: 65536K Total Submissions: 60158   Accepted: 21054 Case Time Limit: 2000MS Description You are working

【bzoj1146】[CTSC2008]网络管理Network 倍增LCA+dfs序+树状数组+主席树

题目描述 M公司是一个非常庞大的跨国公司,在许多国家都设有它的下属分支机构或部门.为了让分布在世界各地的N个部门之间协同工作,公司搭建了一个连接整个公司的通信网络.该网络的结构由N个路由器和N-1条高速光缆组成.每个部门都有一个专属的路由器,部门局域网内的所有机器都联向这个路由器,然后再通过这个通信子网与其他部门进行通信联络.该网络结构保证网络中的任意两个路由器之间都存在一条直接或间接路径以进行通信. 高速光缆的数据传输速度非常快,以至于利用光缆传输的延迟时间可以忽略.但是由于路由器老化,在这些

主席树

#include <iostream> #include <algorithm> #include <cstdio> #include <cstring> #include <cmath> #include <string> #include <cstdlib> #define maxn 100005 using namespace std; int b[maxn],t[maxn],n,m,size,v[maxn],tot