题意:(题目链接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; }