【trie树专题】

【map || trie】P2580 于是他错误的点名开始了

题目背景

XS中学化学竞赛组教练是一个酷爱炉石的人。

他会一边搓炉石一边点名以至于有一天他连续点到了某个同学两次,然后正好被路过的校长发现了然后就是一顿欧拉欧拉欧拉(详情请见已结束比赛CON900)。

题目描述

这之后校长任命你为特派探员,每天记录他的点名。校长会提供化学竞赛学生的人数和名单,而你需要告诉校长他有没有点错名。(为什么不直接不让他玩炉石。)

输入格式

第一行一个整数 n,表示班上人数。接下来 n 行,每行一个字符串表示其名字(互不相同,且只含小写字母,长度不超过 50)。第 n+2 行一个整数 m,表示教练报的名字。接下来 m 行,每行一个字符串表示教练报的名字(只含小写字母,且长度不超过 50)。

输出格式

对于每个教练报的名字,输出一行。如果该名字正确且是第一次出现,输出“OK”,如果该名字错误,输出“WRONG”,如果该名字正确但不是第一次出现,输出“REPEAT”。(均不加引号)

输入输出样例

输入 #1复制

输出 #1复制

说明/提示

对于 40%的数据,n≤1000,m≤2000;

对于 70%的数据,n≤10000,m≤20000;

对于 100%的数据, n≤10000,m≤100000。

T1总是送分的。

注意开数组的大小问题

const int N=5e5+10;
char str[50+5];
int tree[N][26];
int idx;
int cnt[N];

inline void insert(char s[]){
    int p=0;
    for(int i=0;s[i];++i){
        int now=s[i]-'a';
        int &son=tree[p][now];
        if(!son)son=++idx;
        p=son;
    }
}

inline int query(char s[]){
    int p=0;
    for(int i=0;s[i];++i){
        int now=s[i]-'a';
        int &son=tree[p][now];
        if(!son)return 404;//WRONG
        p=son;
    }
    if(cnt[p])return 666;//REPEAT
    cnt[p]++;
    return 100;//OK
}

int main(){
    int n;rd(n);
    rep(i,1,n){
        scanf("%s",str);
        insert(str);
    }
    int q;rd(q);
    while(q--){
        scanf("%s",str);
        int ans=query(str);
        if(ans==404)puts("WRONG");
        else if(ans==666)puts("REPEAT");
        else if(ans==100)puts("OK");
    }
    return 0;
}
int n;
map<string,int>mp;
string s;

int main(){
    int n;rd(n);
    rep(i,1,n){
        cin>>s;
        mp[s]++;
    }
    int q;rd(q);
    while(q--){
        cin>>s;
        if(mp[s]==1){
            puts("OK");
            mp[s]++;
        }
        else if(mp[s]==0){
            puts("WRONG");
        }
        else
            puts("REPEAT");
    }
    return 0;
}

【trie】Phone List

Description

Given a list of phone numbers, determine if it is consistent in the sense that no number is the prefix of another. Let‘s say the phone catalogue listed these numbers:

  • Emergency 911
  • Alice 97 625 999
  • Bob 91 12 54 26

In this case, it‘s not possible to call Bob, because the central would direct your call to the emergency line as soon as you had dialled the first three digits of Bob‘s phone number. So this list would not be consistent.

Input

The first line of input gives a single integer, 1 ≤ t ≤ 40, the number of test cases. Each test case starts with n, the number of phone numbers, on a separate line, 1 ≤ n ≤ 10000. Then follows n lines with one unique phone number on each line. A phone number is a sequence of at most ten digits.

Output

For each test case, output "YES" if the list is consistent, or "NO" otherwise.

Sample Input

2
3
911
97625999
91125426
5
113
12340
123440
12345
98346

Sample Output

NO
YES

SOL:

==构造一棵\(Trie\)树,然后把字符串长度从大到小排序,然后按顺序插入。若在插入的时候\(Trie\)树结点一直不为空,那么该串为其的子串==

头文件大法好!

#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define dwn(i,a,b) for(int i=(a);i>=(b);--i)
template <typename T>inline void rd(T &x){
    x=0;char c=getchar();int flag=0;
    while(!isdigit(c)){flag|=c=='-';c=getchar();}
    while(isdigit(c)){x=x*10+(c^48);c=getchar();}
    x=flag?-x:x;
}
#define mem(a,b) memset(a,b,sizeof(a))
#define ee(i,u) for(int i=head[u];i;i=e[i].next)
/******************************************** Header Template **********************************************/
const int N=1e4+10;
char str[N][10+5];
int tree[N*10][10+5];
int ans=0,idx;

struct zifu{
    int len,id;
    bool operator <(const zifu &rhs)const{
        return len>rhs.len;
    }
}a[N];

inline void insert(char s[]){
    int p=0;
    bool flag=0;
    for(int i=0;s[i];++i){
        int now=s[i]-'0';
        int &son=tree[p][now];
        if(!son){
            son=++idx;
            flag=1;
        }
        p=son;
    }
 //   printf("%d %s\n",flag,s);
    if(flag==0)ans=1;
 //   printf("ans=%d\n",ans);
}

int main(){
    int T;rd(T);
    while(T--){
        //多组数据初始化啊啊啊啊
        mem(tree,0);
        ans=0,idx=0;
        int n;rd(n);
        rep(i,1,n){
            scanf("%s",str[i]);
            a[i].len=strlen(str[i]),a[i].id=i;
        }
        sort(a+1,a+n+1);
        rep(i,1,n){
            insert(str[a[i].id]);
        }
        if(ans==1)puts("NO");
        else puts("YES");
    }
    return 0;
}

【01trie】 最大异或对

const int N=1e5+10,M=3e6+10;
int n;
int a[N];
int tree[M][2];
int idx;

inline void insert(int x){
    int p=0;
    dwn(i,30,0){
        int now=x>>i&1;
        int &son=tree[p][now];
        if(!son)son=++idx;
        p=son;
    }
}

inline int query(int x){
    int res=0,p=0;
    dwn(i,30,0){
        int now=x>>i&1;
        if(tree[p][!now]){
            p=tree[p][!now];
            res+=1<<i;
        }
        else
            p=tree[p][now];
    }
    return res;
}

#undef int
int main(){
#define int long long
    rd(n);
    rep(i,1,n){
        rd(a[i]);
        insert(a[i]);
    }
    int ans=0;
    rep(i,1,n){
        ans=max(ans,query(a[i]));
    }
    printf("%lld\n",ans);
    return 0;
}

【01trie || 树上边权异或值】最长异或值路径

给定一个树,树上的边都具有权值。

树中一条路径的异或长度被定义为路径上所有边的权值的异或和:

⊕ 为异或符号。

给定上述的具有n个节点的树,你能找到异或长度最大的路径吗?

输入格式

第一行包含整数n,表示树的节点数目。

接下来n-1行,每行包括三个整数u,v,w,表示节点u和节点v之间有一条边权重为w。

输出格式

输出一个整数,表示异或长度最大的路径的最大异或和。

数据范围

1≤n≤1000001≤n≤100000,
0≤u,v<n0≤u,v<n,
0≤w<2310≤w<231

输入样例:

4
0 1 3
1 2 4
1 3 6

输出样例:

7

样例解释

样例中最长异或值路径应为0->1->2,值为7 (=3 ⊕ 4)

树上求异或值可以先预处理出val[u]表示u节点到根节点的边权的异或值(用一遍dfs预处理出来),如果我们要求(u,v)的路径异或值,直接将val[u]^val[v]就好(根据异或的性质,他俩lca到根的异或值会变成0).

问题就转化成了1~n的val[i]中,任选两个val[i]使得他俩异或值最大。

这不就是上一道题吗。

const int N=1e5+10;
int n,idx;
int val[N];
int tree[N*30][2];//N个数,每个数可能有30个子节点,值可能有两种情况:0/1

struct edge{
    int v,w,next;
}e[N<<1];

int head[N],edge_num;
inline void adde(int u,int v,int w){
    e[++edge_num].v=v;
    e[edge_num].w=w;
    e[edge_num].next=head[u];
    head[u]=edge_num;
}

inline void dfs(int u,int fa){
    ee(i,u){
        int v=e[i].v,w=e[i].w;
        if(v==fa)continue;
        val[v]=val[u]^w;
        dfs(v,u);
    }
}

inline void insert(int x){
    int p=0;
    dwn(i,30,0){
        int now=x>>i&1;
        int &son=tree[p][now];
        if(!son)son=++idx;
        p=son;
    }
}

inline int query(int x){
    int res=0,p=0;
    dwn(i,30,0){
        int now=x>>i&1;
        if(tree[p][!now]){
            p=tree[p][!now];
            res+=1<<i;
        }
        else
            p=tree[p][now];
    }
    return res;
}

int main(){
    rd(n);
    rep(i,1,n-1){
        int u,v,w;rd(u),rd(v),rd(w);
        adde(u,v,w),adde(v,u,w);
    }
    dfs(0,-1);
    rep(i,1,n){
        insert(val[i]);
    }
    int ans=0;
    rep(i,1,n)
        ans=max(ans,query(val[i]));
    printf("%d\n",ans);
    return 0;
}

【trie】142. 前缀统计 、

给定N个字符串S1,S2…SNS1,S2…SN,接下来进行M次询问,每次询问给定一个字符串T,求S1S1~SNSN中有多少个字符串是T的前缀。

输入字符串的总长度不超过106106,仅包含小写字母。

输入格式

第一行输入两个整数N,M。

接下来N行每行输入一个字符串SiSi。

接下来M行每行一个字符串T用以询问。

输出格式

对于每个询问,输出一个整数表示答案。

每个答案占一行。

输入样例:

3 2
ab
bc
abc
abc
efg

输出样例:

2
0
const int N=1e6+10;
char str[N];
int tree[N][26+5];
int idx,n,m;
int cnt[N];

inline void insert(char s[]){
    int p=0;
    for(int i=0;s[i];++i){
        int now=s[i]-'a';
        int &son=tree[p][now];
        if(!son)
            son=++idx;
        p=son;
    }
    cnt[p]++;
}

inline int query(char s[]){
    int res=0,p=0;
    for(int i=0;s[i];++i){
        int now=s[i]-'a';
        int &son=tree[p][now];
        if(son==0)return res;//一旦找到非前缀立即返回

        res+=cnt[son];
        p=son;
    }
    return res;
}

int main(){
    rd(n),rd(m);
    rep(i,1,n){
        scanf("%s",str);
        insert(str);
    }
    rep(i,1,m){
        scanf("%s",str);
        printf("%d\n",query(str));
    }
    return 0;
}

【断点DP || 01trie】4260: Codechef REBXOR

Description

Input

输入数据的第一行包含一个整数N,表示数组中的元素个数。

第二行包含N个整数A1,A2,…,AN。

Output

输出一行包含给定表达式可能的最大值。

Sample Input

5
1 2 3 1 2

Sample Output

6

HINT

满足条件的(l1,r1,l2,r2)有:(1,2,3,3),(1,2,4,5),(3,3,4,5)。

对于100%的数据,2 ≤ N ≤ 4*105,0 ≤ Ai ≤ 109。

因为两端区间严格不相交,所以预处理出前缀异或和和后缀异或和,然后用(O(n))的时间求最大值

由于是查询区间异或和的最大值,而我们目前只能处理在一堆元素里找俩元素的异或和最大的问题;

根据前缀异或和的性质,如果我们每次把前缀异或和当成元素插入trie的话,就可以保证找到的俩元素异或和是一段区间的的异或和,DP记录一下前缀异或和和后缀异或和。O啦K

const int N=4e5+10;
int n;
int a[N],l[N],r[N];
int tree[N*31][2];
int idx;

inline void insert(int x){
    int p=0;
    dwn(i,30,0){
        int now=x>>i&1;
        int &son=tree[p][now];
        if(!son)son=++idx;
        p=son;
    }
}

inline int query(int x){
    int res=0,p=0;
    dwn(i,30,0){
        int now=x>>i&1;
        if(tree[p][now^1]){
            p=tree[p][now^1];
            res+=1<<i;
        }
        else {
            p=tree[p][now];
        }
    }
    return res;
}

int main(){
    rd(n);
    rep(i,1,n)rd(a[i]);
    int now=0;
    insert(0);
    rep(i,1,n){
        now^=a[i];
        l[i]=max(l[i-1],query(now));
        insert(now);
    }
    mem(tree,0);
    idx=0,now=0;
    dwn(i,n,1){
        now^=a[i];
        r[i]=max(r[i+1],query(now));
        insert(now);
    }
    int ans=0;
    rep(i,1,n-1)
        ans=max(ans,l[i]+r[i+1]);
    printf("%d\n",ans);
//    printf("%.2lf\n",(double)sizeof(tree)/(1<<20));
    return 0;
}

【1A trie 】Shortest Prefixes

每经过一个点,就val[son]++,当前的val==1就立即退出,并输出当前的字串。

Time Limit: 1000MS Memory Limit: 30000K
Total Submissions: 24339 Accepted: 10309

Description

A prefix of a string is a substring starting at the beginning of the given string. The prefixes of "carbon" are: "c", "ca", "car", "carb", "carbo", and "carbon". Note that the empty string is not considered a prefix in this problem, but every non-empty string is considered to be a prefix of itself. In everyday language, we tend to abbreviate words by prefixes. For example, "carbohydrate" is commonly abbreviated by "carb". In this problem, given a set of words, you will find for each word the shortest prefix that uniquely identifies the word it represents.

In the sample input below, "carbohydrate" can be abbreviated to "carboh", but it cannot be abbreviated to "carbo" (or anything shorter) because there are other words in the list that begin with "carbo".

An exact match will override a prefix match. For example, the prefix "car" matches the given word "car" exactly. Therefore, it is understood without ambiguity that "car" is an abbreviation for "car" , not for "carriage" or any of the other words in the list that begins with "car".

Input

The input contains at least two, but no more than 1000 lines. Each line contains one word consisting of 1 to 20 lower case letters.

Output

The output contains the same number of lines as the input. Each line of the output contains the word from the corresponding line of the input, followed by one blank space, and the shortest prefix that uniquely (without ambiguity) identifies this word.

Sample Input

carbohydrate
cart
carburetor
caramel
caribou
carbonic
cartilage
carbon
carriage
carton
car
carbonate

Sample Output

carbohydrate carboh
cart cart
carburetor carbu
caramel cara
caribou cari
carbonic carboni
cartilage carti
carbon carbon
carriage carr
carton carto
car car
carbonate carbona
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
const int N=1e3+5,S=20+5;
int tot;
char s[N][S];
int tree[N*S][30],idx=0;
int val[N*S];

inline void insert(char s[]){
    int p=0;
    for(int i=0;s[i];++i){
        int now=s[i]-'a';
        int &son=tree[p][now];
        if(!son)son=++idx;
        val[son]++;
        p=son;
    }
}

inline void query(char s[]){
    int p=0;
    bool flag=0;
    for(int i=0;s[i];++i){
        int now=s[i]-'a';
        int &son=tree[p][now];
        if(val[son]==1){
            rep(j,0,i)
                printf("%c",s[j]);
            flag=1;
            break;
        }
        p=son;
    }
    if(!flag)cout<<s;
}

int main(){
    while(scanf("%s",s[++tot])!=EOF){
        insert(s[tot]);
    }
    tot--;
    rep(i,1,tot){
        printf("%s ",s[i]);
        query(s[i]);
        puts("");
    }
    return 0;
}

原文地址:https://www.cnblogs.com/sjsjsj-minus-Si/p/11785202.html

时间: 2024-10-06 21:05:21

【trie树专题】的相关文章

poj3630 Phone List (trie树模板题)

Phone List Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 26328   Accepted: 7938 Description Given a list of phone numbers, determine if it is consistent in the sense that no number is the prefix of another. Let's say the phone catalogu

跳跃表,字典树(单词查找树,Trie树),后缀树,KMP算法,AC 自动机相关算法原理详细汇总

第一部分:跳跃表 本文将总结一种数据结构:跳跃表.前半部分跳跃表性质和操作的介绍直接摘自<让算法的效率跳起来--浅谈"跳跃表"的相关操作及其应用>上海市华东师范大学第二附属中学 魏冉.之后将附上跳跃表的源代码,以及本人对其的了解.难免有错误之处,希望指正,共同进步.谢谢. 跳跃表(Skip List)是1987年才诞生的一种崭新的数据结构,它在进行查找.插入.删除等操作时的期望时间复杂度均为O(logn),有着近乎替代平衡树的本领.而且最重要的一点,就是它的编程复杂度较同类

Trie树学习2

数组实现的Trie树 字符容量有限,可以使用链表实现更为大容量的Trie #include <iostream> #include <cstdio> #include <string> #include <cstring> #include <vector> #include <map> #include <set> #include <algorithm> #include <cstdlib> #

trie树(字典树)

1. trie树,又名字典树,顾名思义,它是可以用来作字符串查找的数据结构,它的查找效率比散列表还要高. trie树的建树: 比如有字符串"ab" ,"adb","adc"   可以建立字典树如图: 树的根节点head不存储信息,它有26个next指针,分别对应着字符a,b,c等.插入字符串ab时,next['a'-'a']即next[0]为空,这是申请一个结点放在next[0]的位置,插入字符串db时,next['d'-'a']即next[3]

Trie树

Trie树,即字典树或单词查找树,主要用于大量字符串的检索.去重.排序等操作. 主要原理就是利用字符串的公共前缀建立一棵多叉树,牺牲空间换取时间. 1 //Trie树 2 #include <iostream> 3 #include <string> 4 using std::cin; 5 using std::cout; 6 using std::endl; 7 using std::string; 8 9 const int SIZE = 26; 10 const char B

bzoj4103异或运算 可持久化trie树

要去清华冬令营了,没找到2016年的题,就先坐一坐15年的. 因为n很小,就按照b串建可持久化trie树,a串暴力枚举. 其他的直接看代码. #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; inline int read() { int x=0,f=1,ch=getchar(); while(ch<'0'||ch

hihoCoder 1014 Trie树

#1014 : Trie树 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi和小Ho是一对好朋友,出生在信息化社会的他们对编程产生了莫大的兴趣,他们约定好互相帮助,在编程的学习道路上一同前进. 这一天,他们遇到了一本词典,于是小Hi就向小Ho提出了那个经典的问题:“小Ho,你能不能对于每一个我给出的字符串,都在这个词典里面找到以这个字符串开头的所有单词呢?” 身经百战的小Ho答道:“怎么会不能呢!你每给我一个字符串,我就依次遍历词典里的所有单词,检查你给我的字

HDU 1251 Trie树模板题

1.HDU 1251 统计难题  Trie树模板题,或者map 2.总结:用C++过了,G++就爆内存.. 题意:查找给定前缀的单词数量. #include<iostream> #include<cstring> #include<cmath> #include<queue> #include<algorithm> #include<cstdio> #define max(a,b) a>b?a:b #define F(i,a,b

hiho一下 第二周&amp;第四周:从Trie树到Trie图

hihocoder #1014 题目地址:http://hihocoder.com/problemset/problem/1014 hihocoder #1036 题目地址: http://hihocoder.com/problemset/problem/1036 trie图其实就是trie树+KMP #1014trie树 #include<stdio.h> #include <algorithm> #include <cstring> #include <str