CQOI2016 路由表Route - Trie
分析:
正解是Trie吧。考完之后想想真的是这样,题目还明确说了不会添加目的地址和掩码长度都一样的项,那么对于每一个01串建立Trie树,在相应掩码结束的位置记录这个串位于添加表中的位置pos。每次询问的时候扫一遍Trie对应询问的串,对每一个扫过的位置上记录的pos排序(最多32个,不会超时)。按照题目的要求模拟一下,算出答案。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 1000000
struct node{
int pos,len;
}b[MAXN+10];
int n,a[MAXN+10][5],qua[MAXN+10][5],cnta,cntq;
int Trie[MAXN*32+10][2],cntu,root,pos[MAXN*32+10],cntb;
void read()
{
char opt[20],str[100];
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%s",opt);
if(opt[0]=='A'){
scanf("%s",str);
int val=0,L=0,lens=strlen(str);
for(int i=0;i<lens;i++){
if(i&&str[i-1]=='/'){
for(;i<lens;i++)
L=L*10+str[i]-'0';
break;
}
int t=0;
for(;str[i]!='.'&&str[i]!='/'&&i<lens;i++)
t=t*10+str[i]-'0';
val=val*256+t;
}
++cnta;
a[cnta][0]=val,a[cnta][1]=L;
}
else{
++cntq;
scanf("%s%d%d",str,&qua[cntq][1],&qua[cntq][2]);
int lens=strlen(str),val=0;
for(int i=0;i<lens;i++){
int t=0;
for(;str[i]!='.'&&i<lens;i++)
t=t*10+str[i]-'0';
val=val*256+t;
}
qua[cntq][0]=val;
}
}
}
void Insert(char *str,int len,int id)
{
int t=root;
for(int i=0;i<len;i++){
if(!Trie[t][str[i]-'0'])
Trie[t][str[i]-'0']=++cntu;
t=Trie[t][str[i]-'0'];
}
pos[t]=id;
}
void Build()
{
char str[100];
memset(str,0,sizeof str);
for(int i=1;i<=cnta;i++){
for(int j=0;j<32;j++)
str[31-j]=(a[i][0]&(1<<j))?'1':'0';
Insert(str,a[i][1],i);
}
}
bool cmp(node a0,node b0){
return a0.pos<b0.pos;
}
void workout()
{
char str[100];
memset(str,0,sizeof str);
for(int i=1;i<=cntq;i++){
for(int j=0;j<32;j++)
str[31-j]=(qua[i][0]&(1<<j))?'1':'0';
int t=root,ans=0;
cntb=0;
for(int j=0;j<32;j++){
if(!Trie[t][str[j]-'0'])
break;
t=Trie[t][str[j]-'0'];
if(pos[t]&&pos[t]<=qua[i][2]){
++cntb;
b[cntb].pos=pos[t];
b[cntb].len=j+1;
}
}
sort(b+1,b+cntb+1,cmp);
int pnt=-1;
for(int j=1;j<=cntb;j++)
if(pnt<b[j].len){
pnt=b[j].len;
if(b[j].pos>=qua[i][1])
ans++;
}
printf("%d\n",ans);
}
}
int main()
{
//freopen("route.in","r",stdin);
//freopen("route.out","w",stdout);
read();
Build();
workout();
return 0;
}