题意:(题目链接http://hihocoder.com/problemset/problem/1289)给定n个IP地址,后面可能跟着一个前缀长度,并给出这个IP地址是allow还是deny,然后给出m个ip地址,判断应该allow还是deny。匹配的规则是在n个地址表里从前往后,碰到匹配就输出,如果全部不匹配就allow。
思路:暴搜肯定是会超时的,这里用trie。将n个地址看成一个二进制串,插入trie中,然后匹配。trie结点要标记先后顺序和allow与否。注意一个WA点:如果有两个地址相同,那么记录的肯定是之前的。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
using namespace std;
#define clr(s,t) memset(s,t,sizeof(s))
#define INF 0x3fffffff
#define N 100005
int n,m;
char tmp[9],res[35];
struct node{
node *next[2];
bool allow;
int num;
node(){
allow = -1;
num = INF;
memset(next, 0, sizeof(next));
}
};
node *root;
int allow = -1;
char* myitoa(int x){
for(int i = 7;i>=0;i--){
tmp[i] = (x&1)+'0';
x >>= 1;
}
return tmp;
}
char* extract(int a,int b,int c,int d,int e){
strcpy(res,myitoa(a));
strcpy(res+8,myitoa(b));
strcpy(res+16,myitoa(c));
strcpy(res+24,myitoa(d));
res[e] = '\0';
return res;
}
void insert(bool flag,int id,char *str){
node *p = root,*q;
for(int i = 0;str[i];i++){
if(p->next[str[i]-'0'] == NULL){
q = new node();
p->next[str[i]-'0'] = q;
}
p = p->next[str[i]-'0'];
}
if(p->num == INF){
p->allow = flag;
p->num = id;
}
}
bool find(char *str){
node *p = root;
bool ans = true;
int pos = INF;
for(int i = 0;str[i];i++){
if(p->num<pos){
pos = p->num;
ans = p->allow;
}
if(p->next[str[i]-'0'] == NULL)
break;
p = p->next[str[i]-'0'];
}
if(p && p->num<pos)
ans = p->allow;
return ans;
}
int main(){
int a,b,c,d,e;
char cmd[10],ch;
scanf("%d %d",&n,&m);
tmp[8] = '\0';
root = new node();
for(int i = 0;i<n;i++){
scanf("%s",cmd);
scanf("%d.%d.%d.%d",&a,&b,&c,&d);
ch = getchar();
if(ch == '/')
scanf("%d",&e);
else
e = 32;
if(!strcmp(cmd, "allow"))
insert(true,i,extract(a,b,c,d,e));
else
insert(false,i,extract(a,b,c,d,e));
}
for(int i = 0;i<m;i++){
scanf("%d.%d.%d.%d",&a,&b,&c,&d);
if(find(extract(a, b, c, d, 32)))
printf("YES\n");
else
printf("NO\n");
}
return 0;
}