题目大意
由于还没有拿到题目大概先说一下题意吧:首先给你一个空空的路由器,大家然后我们对于一个空的路由表有两种操作
- 插入一个新的IP寻址方式
查询一个IP在[L,R]中最终寻找到的IP被修改了多少次
这里IP的寻找方式是这样给出的我们有A.B.C.D四位数字外加一个L,首先我们将A.B.C.D转换为二进制,然后从A开始比较L为如果和询问的IP转换成二进制如果前面L位可以匹配我们认为这个是成功匹配的但是如果有多个成功匹配的我们取其中L最长的。
题目解析
思路非常简单,首先对于插入操作我们转换成一个二叉树,由每一个IP的01来决定位置利用AC自动机的思路,在结束位置打上标记标记IP的id同时我们寻找从根到当前插入的IP的路径上的所有点上有标记的深度最大的那一个(因为深度越大代表着L越大)然后我们将当前ID的父亲设置为找到的那个IP然后变换次数设置为他的+1这样每次插入就不会超过32次其实近似于O(log L)然后我们处理查询,首先将当前串在整个二叉树上走记录最深的节点(代表L最大)然后在L的IP的链上暴力查询[L, R]区间同理因为深度最大只有32所以也是近似于O(log L)总的复杂度就是O(nlog L)
代码
#include <cstdio>
#include <cstring>
const int MAXN = 1000000;
struct node{
int ch[2], target;
}pool[MAXN*32+10];
int ecnt;
struct IP{
int fa, dep;
}ips[MAXN+10];
int icnt;
void Insert(int *s, int L){
int u = 0, tar = 0;
for(int i=0;i<L;i++){
if(!pool[u].ch[s[i]])
pool[u].ch[s[i]]=++ecnt;
if(pool[u].tar)
tar = pool[u].tar;
u = pool[u].ch[s[i]];
}
pool[u].target = ++icnt;
ips[icnt].fa = tar;
ips[icnt].dep = ips[tar].dep + 1;
}
int Query(int *s, int l, int r){
int u = 0, tar = 0;
for(int i=0;i<32;i++){
if(pool[u].tar)
tar = pool[u].tar;
if(!pool[u].ch[s[i]]) break;
u = pool[u].ch[s[i]];
}
if(pool[u].tar)
tar = pool[u].tar;
if(tar < l) return 0;
while(tar > r) tar = ips[tar].fa;
int ptar = tar;
while(ptar >= l) ptar = ips[ptar].fa;
return ips[tar].dep - ips[ptar].dep;
}
int num[32];
void GetIP(int a, int b, int c, int d){
for(int i=7;i>=0;i--) num[i]=a%2, a/=2;
for(int i=15;i>=8;i--) num[i]=b%2, b/=2;
for(int i=23;i>=16;i--) num[i]=c%2, c/=2;
for(int i=31;i>=24;i--) num[i]=d%2, d/=2;
}
void Read(int &u){
char ch;
while(ch=getchar(), ch<'0'||ch>'9');
u = ch-'0';
while(ch=getchar(), ch>='0'&&ch<='9')
u = u*10+ch-'0';
ungetc(ch, stdin);
}
int main(){
int n, a, b, c, d, L;
scanf("%d", &n);
char ord[10];
for(int i=1;i<=n;i++){
scanf("%s", ord);
if(ord[0] == 'A'){
Read(a); Read(b); Read(c); Read(d);
Read(L);
GetIP(a,b,c,d);
Insert(num, L);
}else{
Read(a); Read(b); Read(c); Read(d);
GetIP(a,b,c,d);
Read(a); Read(b);
printf("%d\n", Query(num, a, b));
}
}
return 0;
}