题目:http://hihocoder.com/problemset/problem/1289
分析:有N条已知的前缀字符串,回答M个query,每个query找到这N个字符串中第一个匹配的项,自然的想到O(length)复杂度的字典树Trie。
由于
(1)1 <= N, M <= 10^5
(2)字符串仅由01组成 >>> Trie的每个node仅含有2个子节点
(3)每个字符串最多包含32个字符 >>> 一个字符串最多需要32个节点来表示
所以,不超过32N(< 3.2*10^6)个节点就可以表示这N条字符串,并且查询不超过32M(< 3.2*10^6)个节点就能完成全部M个query
需要注意的是,和普通的“字符串是否在Trie上”查询不同,题目中的查询要求找到第一个匹配的前缀,所以我们必须在经过每个节点时“看看这个节点的序号是不是更小”
下面是AC代码,对“最多32位的、仅包含01的”字符串,这里用了一个int变量进行表示
#include
using namespace std;
const int MAX_N = 100005 * 32;
const int kUndefine = 0;
const int kDeny = 1;
const int kAllow = 2;
struct Node
{
Node* ch[2];
int state; // whether to allow the ip(formed by edges from root to this node)
int order; // the rule's index
};
Node nodes[MAX_N] = {0}; // initialize all node states to kUndefine
int idx = 0; // index of the next available node
void insert(Node* p, int ip, int len, int state, int order)
{
unsigned b = 1 << 31; // as we want an unsigned right shift
for(; len--; b >>= 1){
int i = b & ip ? 1 : 0;
if(p->ch[i] == 0){
// new a child node
p->ch[i] = nodes + idx++;
}
p = p->ch[i];
}
// we can not override former rules with latter ones
if(p->state == kUndefine || p->order > order){
p->state = state;
p->order = order;
}
}
int check(Node* p, int ip)
{
int state = kUndefine, order;
unsigned b = 1 << 31;
for(; b; b >>= 1){
int i = b & ip ? 1 : 0;
if(p->ch[i] == 0) break; // stop matching here
p = p->ch[i];
if(p->state != kUndefine){
// so p is an ending node here
if(state == kUndefine || order > p->order){
state = p->state;
order = p->order;
}
}
}
return state;
}
int main()
{
int i, n, m, a, b, c, d, ip, len, state, global = kUndefine;
char s[8];
scanf("%d%d", &n, &m);
// build trie
Node* root = nodes + idx++;
for(i = 0; i < n && global == kUndefine; ++i){
// input: rule ip[/len]
scanf("%s %d.%d.%d.%d", s, &a, &b, &c, &d);
ip = (a << 24) | (b << 16) | (c << 8) | d;
if(getchar() == '/') scanf("%d", &len);
else len = 32;
// insert trie
state = s[0] == 'a' ? kAllow : kDeny;
if(len == 0){
// the very last rule that counts (matching everything)
global = state;
}
else insert(root, ip, len, state, i);
}
// eat all rules after the matching-everything rule
for(; i < n; ++i){
scanf("%s %d.%d.%d.%d", s, &a, &b, &c, &d);
if(getchar() == '/') scanf("%d", &len);
}
// do query
for(i = 0; i < m; ++i){
scanf("%d.%d.%d.%d", &a, &b, &c, &d);
ip = (a << 24) | (b << 16) | (c << 8) | d;
state = check(root, ip);
if(state == kUndefine){
// no matched prefix, use global rule
state = global;
}
puts(state == kDeny ? "NO" : "YES");
}
return 0;
}