码迷,mamicode.com
首页 > 其他好文 > 详细

【trie树专题】

时间:2019-11-03 10:35:17      阅读:67      评论:0      收藏:0      [点我收藏+]

标签:ber   tin   alt   lin   bre   tps   empty   答案   script   

【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;
}

【trie树专题】

标签:ber   tin   alt   lin   bre   tps   empty   答案   script   

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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!