NKOJ 3615(CQOI 2016) 路由表(trie)

P3615【CQOI2016 Day2】路由表

问题描述
这里写图片描述

输入格式

第一行,一个整数n,表示操作次数。
接下来n行,每行描述一次操作,操作有两种:
A D/L
其中D为一个IP地址,L为整数(1<=L<=32)。添加一条表项至路由表,其目的地址为D,掩码长度为L。下一条地址由于没有用到,故省略。
Q D a b
其中,D为一个IP地址,a、b为正整数(a<=b).查询从第a到第b次调价表项期间(含a,b),目的地址D的路由表项选择发生了多少次变化。保证查询时表中至少有b个表项目

输出格式

若干行,每行一个整数,表示对应查询操作

样例输入

11
A 0.0.0.0/8
Q 1.2.3.4 1 1
A 1.0.0.0/9
A 1.128.0.0/10
A 1.0.0.0/10
A 1.0.0.0/8
Q 1.2.3.4 1 5
A 1.2.0.0/16
A 1.2.3.1/32
Q 1.2.3.4 5 7
Q 1.2.3.1 5 7

样例输出

0
2
1
2

提示

对于一次查询的一种理解方式是:无视其它所有查询操作,只看添加操作。先清空路由表,然后执行第1到a-1次添加操作。之后再统计第a到b次添加操作过程中,统计匹配改变的次数。
设一条表项的掩码长度为L,数据保证将目的地址转为二进制串后,末尾的32-L位均为0

数据范围:n<= 105


此题只需要将IP转化为一个字符串后添加入一个trie中,每次查询时暴力匹配,将1到b次添加操作之间的串拿出来,按照操作顺序排序,然后按题目要求搞就行了。由于要求改变量,所以必须知道1-a-1次操作后的情况。

附上代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
struct node{int son[2],num,len;}trie[5000000],A[123456];
int tot=1,rt=1,cnt;
char s[45];
bool cmp(node a,node b)
{return a.num<b.num;}
void CHA(int l,int x)
{
    for(int i=7;i>=0;i--)
    s[++l]=(1&(x>>i))+48;
}
void TRA(int a,int b,int c,int d)
{
    CHA(0,a);
    CHA(8,b);
    CHA(16,c);
    CHA(24,d);
}
void Ins(int L,int k)
{
    int p=1,i,c;
    for(i=1;i<=L;i++)
    {
        c=s[i]-48;
        if(!trie[p].son[c])trie[p].son[c]=++tot;
        p=trie[p].son[c];
    }
    trie[p].num=k;
    trie[p].len=L;
}
void Find(int L,int b)
{
    int p=1,i,c;
    for(i=1;i<=L;i++)
    {
        c=s[i]-48;
        if(!trie[p].son[c])return;
        p=trie[p].son[c];
        if(trie[p].num<=b&&trie[p].num)
        {
            cnt++;
            A[cnt].num=trie[p].num;
            A[cnt].len=trie[p].len;
        }
    }
}
void ADD(int k)
{
    int a,b,c,d,l;
    scanf("%d.%d.%d.%d/%d",&a,&b,&c,&d,&l);
    TRA(a,b,c,d);Ins(l,k);
}
void Solve()
{
    int i,a,b,c,d,l,r,k=0,ans=0;cnt=0;
    scanf("%d.%d.%d.%d%d%d",&a,&b,&c,&d,&l,&r);
    TRA(a,b,c,d);Find(32,r);
    if(cnt==0){puts("0");return;}
    sort(A+1,A+cnt+1,cmp);
    for(i=1;i<=cnt;i++)
    if(A[i].len>k)
    {
        k=A[i].len;
        if(A[i].num>=l)ans++;
    }
    printf("%d\n",ans);
}
int main()
{
    int i,k=0,n;char a;
    scanf("%d",&n);
    for(i=1;i<=n;i++)
    {
        a=getchar();
        while(a!='A'&&a!='Q')a=getchar();
        if(a=='A')ADD(++k);
        else Solve();
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
CMU 15445 Trie是一个在卡耐基梅隆大学开设的计算机科学课程中介绍的一种数据结构,用于高效地存储和搜索字符串。字典树,即Trie树,是一种多叉树的形式,每个节点代一个字符串的字符。 Trie的优点是可以快速地进行字符串的查找操作。相比于哈希等其他数据结构,Trie可以在O(L)的时间内完成字符串的插入、删除和查找操作,其中L是字符串的长度。这是因为Trie使用径压缩和共享共同前缀的方式节省了空间。 Trie的基本操作包括插入、删除和查找。在插入时,我们遍历要插入的字符串的字符序列,在Trie中沿着相应的径向下移动,并在需要的时候创建新的节点。当到达字符串的末尾时,我们在最后一个节点上标记该字符串已经结束。删除操作与插入操作类似,只是需要在到达字符串的末尾时将节点上的标记移除。 查找操作是Trie的主要优势之一。我们可以通过从根节点开始遍历Trie并沿着相应的径移动,直到达到目标字符串的末尾。如果在遍历过程中遇到了空节点或者没有相应的径,那么目标字符串不存在于Trie中。如果当我们到达目标字符串的末尾时,发现最后一个节点上的标记,那么说明目标字符串存在于Trie中。 Trie的应用广泛,包括拼写检查、自动完成、IP的构建等。拥有快速的插入、删除和查找操作使得Trie成为处理大量字符串的理想数据结构。同时,通过径压缩和共享共同前缀的方式,Trie能够充分节省内存空间,使其在存储大规模字符串时更加高效。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值