字典树(trie树)

835. Trie字符串统计

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N=1e5+10;
char str[N];
int son[N][26], cnt[N], idx;
// 0号点既是根节点
// son[][]存储树中每个节点的子节点
// cnt[]存储以每个节点结尾的单词数量,以当前结点为结尾的单词有多少个
//idx是我们当前用的是哪个下标
// 插入一个字符串
void Insert(char *str)
{
    int p = 0;//当前结点为根节点
    for (int i = 0; str[i]; i ++ )
    {
        int u = str[i] - 'a';//将要插入的a-z映射成0-25
        if (!son[p][u]) son[p][u] = ++ idx;//如果当前结点不存在u这个儿子结点,就创建出这个儿子结点
        p = son[p][u];//令儿子结点为当前结点
    }
    cnt[p] ++ ;//字符串个数加1
}

// 查询字符串出现的次数
int query(char *str)
{
    int p = 0;
    for (int i = 0; str[i]; i ++ )
    {
        int u = str[i] - 'a';
        if (!son[p][u]) return 0;
        p = son[p][u];
    }
    return cnt[p];//返回以p结尾的单词数量
}


int main()
{
    int n;
    cin>>n;
    while(n--)
    {
        char c;
        scanf(" %c %s",&c,str);
        if(c=='I')Insert(str);
        else
        {
            printf("%d\n",query(str));
        }
    }

 	return 0;
}//&&(k==0||k==4||l==0||l==4||r==0||r==4)
//5min

1471:【例题1】Phone List

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N=1e5+10;
int tree[N][10];
int sum[N];
int cnt=0;
void Insert(char s[])
{
    int root = 0;
    for(int i=0;s[i];i++)
    {
        int id = s[i]-'0';
        if(!tree[root][id])tree[root][id]=++cnt;

        root = tree[root][id];
        sum[root]++;
    }
}
int Search(char s[])
{
    int root = 0;
    for(int i = 0;s[i];i++)
    {
        int id = s[i]-'0';
        if(!tree[root][id])return 0;
        root = tree[root][id];
    }
    return sum[root];
}

int main()
{
    ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        cnt  = 0;
        memset(tree,0,sizeof(tree));
memset(sum,0,sizeof(sum));
        char s[10005][15];
        cin>>n;
        for(int i=0;i<n;i++)
        {
            cin>>s[i];
            Insert(s[i]);
        }
        int flag=0;
        for(int i=0;i<n;i++)
        {
            flag= max(flag,Search(s[i]));
        }
        if(flag<2)cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
    return 0;
}

1472:【例题2】The XOR Largest Pair

板子题

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N=1e5+10;
/*
第一维的大小是绝对位置,绝对位置的话是数的个数乘以位数,
第一位的大小等于树的结点个数,结点个数跟数的个数以及这个数的长度有关
*/
int tree[32*N][2];
int sum[32*N];
int cnt=0;
void Insert(int s)
{
    int root = 0;
    for(int i=31;i>=0;i--)
    {
        int id = 1&(s>>i);
        if(!tree[root][id])tree[root][id]=++cnt;

        root = tree[root][id];
        sum[root]++;
    }
}
int Search(int s)
{
    int root = 0;
    int ans=0;
    for(int i = 31;i>=0;i--)
    {
        int id = 1&(s>>i);
        if(tree[root][!id])
        {
            ans+=(1<<i);
            root=tree[root][!id];
        }
        else
         root = tree[root][id];
    }
    return ans;
}

int main()
{
    ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);


        int n;
        cnt  = 0;
        memset(tree,0,sizeof(tree));
        memset(sum,0,sizeof(sum));
        int s[100005];
        cin>>n;
        for(int i=0;i<n;i++)
        {
            cin>>s[i];
            Insert(s[i]);
        }
        int ans=0;
        for(int i=0;i<n;i++)
          ans=max(ans,Search(s[i]));
        cout<<ans<<endl;

    return 0;
}

1478:The xor-longest Path
描述:原题来自:POJ 3764
给定一棵 n 个点的带权树,求树上最长的异或和路径。

思路:异或和路径(u,v)可以转换为f(1,u)^f(1,v),那么我们就可以以节点1为跟搜索遍历到每一个节点的异或和路径,放到数组里,这样就转化为,在一个数组里,取两个数异或,得到的数最大是多少,刚好这是模板题,就可以做了。

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N=1e5+10;
/*
第一维的大小是绝对位置,绝对位置的话是数的个数乘以位数,
第一位的大小等于树的结点个数,结点个数跟数的个数以及这个数的长度有关
*/
int tree[32*N][2];
int a[N],vis[N];
int sum[32*N];
int cnt=0;
void Insert(int s)
{
    int root = 0;
    for(int i=30;i>=0;i--)
    {
        int id = 1&(s>>i);
        if(!tree[root][id])tree[root][id]=++cnt;

        root = tree[root][id];
        sum[root]++;
    }

}
int Search(int s)
{
    int root = 0;
    int ans=0;
    for(int i=30;i>=0;i--)
    {
        int id = 1&(s>>i);
        if(tree[root][!id])
        {
            root=tree[root][!id];
            ans|=(1<<i);
        }
        else
        {
            root=tree[root][id];
        }
    }
    //cout<<"ans="<<ans<<endl;
    //cout<<"sum1="<<sum1[root]<<endl;
    return ans;
}
int head[N];
struct edge
{
    int w,to,next;
}e[N*2];//定义边的三个信息,w表示边权,to表示边的终点,next表示上一条边
void add(int x,int y,int z)//链式前向星存边
{
    e[cnt].to=y;
    e[cnt].w=z;
    e[cnt].next=head[x];//next表示以x为起点的上一条边的编号
    head[x]=cnt++;//head[x]表示以x为起点的最后一条边的编号
}
void dfs(int u,int w)
{
    a[u]=w;
    vis[u]=1;
    for(int i=head[u];i!=-1;i=e[i].next)
    {
        int v=e[i].to;
        if(!vis[v])
        {
            dfs(v,w^e[i].w);
        }
    }
}

int main()
{
    ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
    int n;
    cin>>n;
    memset(head,-1,sizeof(head));
    for(int i=0;i<n-1;i++)
    {
        int x,y,z;
        cin>>x>>y>>z;
        add(x-1,y-1,z);
        add(y-1,x-1,z);
    }
    dfs(0,0);
    /*for(int i=0;i<n;i++)
        cout<<a[i]<<" ";*/
    //cout<<endl;
    cnt=0;
    for(int i=0;i<n;i++)
    {
        Insert(a[i]);
    }
    int ma=0;
    for(int i=0;i<n;i++)
    {
        ma=max(ma,Search(a[i]));
    }
    cout<<ma<<endl;
    return 0;
}

Xor sum

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N=1e5+10;
/*
第一维的大小是绝对位置,绝对位置的话是数的个数乘以位数,
第一位的大小等于树的结点个数,结点个数跟数的个数以及这个数的长度有关
*/
int tree[15*N][2];
int sum[15*N];
int cnt=0,k;
void Insert(int s,int index)
{
    int root = 0;
    for(int i=31;i>=0;i--)
    {
        int id = 1&(s>>i);
        if(!tree[root][id])tree[root][id]=++cnt;

        root = tree[root][id];
        if(sum[root]!=0)
        sum[root]=min(sum[root],index);
        else sum[root]=index;
    }
}

int Search(int s)
{
    int root = 0;
    int ans=0;
    for(int i = 31;i>=0;i--)
    {
        int id = 1&(s>>i);
        if(tree[root][!id])
        {
            ans+=(1<<i);
            root=tree[root][!id];
        }
        else
         root = tree[root][id];
        if(ans>=k)
        {
            return sum[root];
        }
    }
    return -1;
}

int main()
{
    ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        cnt  = 0;
        memset(tree,0,sizeof(tree));
        //memset(sum,0,sizeof(sum));
        int a[100005],s[100005];
        cin>>n>>k;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
        }
        for(int i=1;i<=n;i++)
        {
            s[i]=s[i-1]^a[i];
            Insert(s[i],i);
        }

        int mi=999999999;
        int l,r;
        int flag=0;
        for(int i=0;i<=n;i++)
        {
            int t=Search(s[i]);
            if(t!=-1)
            {
                flag=1;
                if(abs(i-t)<mi)
                {
                    mi=min(mi,abs(i-t));
                    l=i+1;
                    r=t;
                }


            }
        }
        if(flag)
        cout<<l<< " "<<r<<endl;
        else cout<<-1<<endl;
        for(int i=0;i<=cnt;i++)
            sum[i]=0;
    }


    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值