4523: [Cqoi2016]路由表
Time Limit: 30 Sec Memory Limit: 512 MB
Submit: 213 Solved: 134
Description
路由表查找是路由器在转发IP报文时的重要环节。通常路由表中的表项由目的地址、掩码、下一
跳(Next Hop)地址和其他辅助信息组成。例如:
当路由器收到一个IP报文时,会将报文中的目的IP地址与路由表中的表项逐条进行比较,选
择匹配且最明确的表项,将报文转发给该表项中指定的下一跳。
匹配的过程是将报文中的目的地址和表项中的目的地址分别转为二进制串,再查看表项中的掩
码长度,若掩码长度为x,则将两个二进制串的前x位进行比较,如果相同则认为匹配。
所谓最明确是指在有多个表项匹配时,总是掩码长度最大的表项。也可以理解为匹配的二进制
位最多的项。
IP地址转为二进制串的操作是把地址中4个整数(一定在y到255的范围内)分别转为8位
二进制数,再顺序拼接起来,得到一个32位的二进制串。例如,192.168.1.253转为二进制串后为
11000000 10101000 00000001 11111101
我们以报文的目的地址为8.8.8.8为例,说明其在上述路由表的匹配过程。
上表将地址均转为二进制串,并用红色标记出待比较的位(由掩码长度决定)。将红色部分与
报文中的目的地址比较,可知0.0.0.0/1、8.8.8.0/24、8.8.8.8、32均能够匹配。路由器从中选取掩
码长度最长(/32)的表项8.8.8.8/32,将报文转发给其对应的下一跳地址192.168.1.253。
在实际的核心路由器中,路由表通常较大(现在互联网的全局路由表已经接60万条记录),
并且会随着新接入设备不断扩张。为了分析路由表变化对转发产生的影响,网络工程师想要知道
一段时间内某个IP地址的路由表项选择发生了多少次变化(变化是指由于最明确匹配等因素选择
了不同的表项,不考虑下一跳地址)。
Input
第一行为整数M,表示共有M次操作。接下来M行,每行描述一次操作。操作有两种:
A D/L
其中.为一个IP地址,G为整数(1≤L≤32)。添加一条表项至路由表,其目的地址为
D掩码长度为L。下一跳地址由于没有用到,故省略。
Q D a b
其中D为一个IP地址,a,b为正整数(a≤b)。查询从第a次至第b次添加表项期间(含
a、b),目的地址D的路由表项选择发生了多少次变化。保证查询时表中至少有b个表项。
N<=10^6数据保证不会重复添加目的地址和掩码长度都相同的表项。
Output
包含若干行,每行仅有一个整数,依次对应每个查询操作。
Trie树乱搞
天哪,这数据给的太良心了!
将所有字符串插入Trie树中,在结束为止记录一个时间戳。
然后对于每组询问,将Trie树上那一条链的信息拿出来,然后随便乱搞一下就可以了。
#include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<cstring> #include<algorithm> #define F(i,j,n) for(int i=j;i<=n;i++) #define D(i,j,n) for(int i=j;i>=n;i--) #define ll long long #define pa pair<int,int> #define N 33000000 using namespace std; int n,cnt=1,tot; int a[50],b[50],c[N][2],tag[N]; inline int read() { int x=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } void add() { int x,len,now=1; F(i,0,3) { x=read(); D(j,8,1) a[j+i*8]=x&1,x>>=1; } len=read(); F(i,1,len) { if (!c[now][a[i]]) c[now][a[i]]=++cnt; now=c[now][a[i]]; } tag[now]=++tot; } void query() { int x,l,r,len=0,now=1; F(i,0,3) { x=read(); D(j,8,1) a[j+i*8]=x&1,x>>=1; } l=read();r=read(); F(i,1,32) { if (!c[now][a[i]]) break; now=c[now][a[i]]; if (tag[now]&&tag[now]<l) len=0; if (tag[now]>=l&&tag[now]<=r) { while (len&&b[len]>=tag[now]) len--; b[++len]=tag[now]; } } printf("%d\n",len); } int main() { n=read(); F(i,1,n) { char ch=getchar();while (ch!='A'&&ch!='Q') ch=getchar(); if (ch=='A') add(); else query(); } return 0; }