1. 程式人生 > >2014 西安站 I International Collegiate Routing Contest(trie)

2014 西安站 I International Collegiate Routing Contest(trie)

題目連結:這裡

題意:輸入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; }