2014 西安站 I International Collegiate Routing Contest(trie)
阿新 • • 發佈:2019-02-08
題目連結:這裡
題意:輸入IPv4地址空間中的一些子網號,構成一個網路集合。
輸出最小的一個網路集合,要求其與輸入集合沒有交集,且相對IPv4地址空間全集,是輸入集合的補集。輸出集合包含的子網號,格式遵循網路規範
做法:tire樹,把所有輸入的子網插入trie裡面,然後遍歷一下,如果一個結點的左兒子和右兒子有一個是標記過的,就輸出沒有標記的那個兒子的子網。
#include <bits/stdc++.h>
using namespace std;
#define pii pair<int, int>
#define MP make_pair
#define LL long long
#define ls (i << 1)
#define rs (ls | 1)
#define md (ll + rr >> 1)
#define lson ll, md, ls
#define rson md + 1, rr, rs
#define eps 1e-8
#define inf 0x3f3f3f3f
#define mod 1000000007
#define N 100010
#define M 200020
#define fi first
#define se second
char buf[32000000],*pt = buf,*o = buf;
int getint(){
int f = 1,x = 0;
while((*pt != '-') && (*pt < '0' || *pt > '9')) pt ++;
if(*pt == '-') f = -1,pt ++; else x = *pt++ - 48;
while(*pt >= '0' && *pt <= '9') x = x * 10 + *pt ++ - 48;
return x * f;
}
char getch(){
char ch;
while(*pt < 'A' || *pt > 'Z') pt ++;
ch=*pt;pt++;
return ch;
}
int ch[N*30][2], cnt, tot, n;
bool vis[N*30];
pair<LL, int> p[N];
int insert(LL v, int k){
int u = 1;
for(int i = 31; i >= 0 && k; --i, --k){
int c = v >> i & 1;
if(!ch[u][c]){
ch[u][c] = ++tot;
memset(ch[tot], 0, sizeof ch[tot]);
vis[tot] = 0;
}
u = ch[u][c];
}
vis[u] = 1;
}
void print(LL v, int dep){
v <<= dep;
int a = v >> 24;
v ^= (LL)a << 24;
int b = v >> 16;
v ^= (LL)b << 16;
int c = v >> 8;
v ^= (LL)c << 8;
int d = v;
printf("%d.%d.%d.%d/%d\n", a, b, c, d, 32 - dep);
}
int query(int u, LL x, int dep){
if(u == 0 || vis[u]) return vis[u];
if(dep == -1)
return vis[u];
int p1 = query(ch[u][0], x << 1, dep - 1);
int p2 = query(ch[u][1], x << 1 | 1, dep - 1);
if(p1 && !p2){
p[cnt++] = MP(x << 1 | 1, dep);
}
else if(!p1 && p2){
p[cnt++] = MP(x << 1, dep);
}
return p1 | p2;
}
int main(){
int cas, kk = 0;
scanf("%d", &cas);
while(cas--){
scanf("%d", &n);
tot = 1;
memset(ch[tot], 0, sizeof ch[tot]);
memset(ch[0], 0, sizeof ch[0]);
vis[0] = vis[1] = 0;
for(int i = 0; i < n; ++i){
int a, b, c, d, k;
scanf("%d.%d.%d.%d/%d", &a, &b, &c, &d, &k);
LL v = 1LL * a * (1 << 24) + b * (1 << 16) + c * (1 << 8) + d;
insert(v, k);
}
printf("Case #%d:\n", ++kk);
if(n == 0){
printf("1\n0.0.0.0/0\n"); continue;
}
cnt = 0;
query(1, 0LL, 31);
printf("%d\n", cnt);
for(int i = 0; i < cnt; ++i)
print(p[i].fi, p[i].se);
}
return 0;
}