网络知识比较差,造成看题非常吃力。
题目大意:有多个政策,每个政策里面有很多子网,E 表示加入一个政策,D表示禁止一个政策,F就是询问ip1,ip2是不是在同一个政策中。
思路:子网有个特点前缀相同,对于E操作,不难想到用字典树来维护所有子网(即ip的前缀),每个节点用一个vector保存该子网(即前缀)所属于的所有政策的标号。对于D操作,我们用一个数组维护该政策可不可用,对于F就是先把ip1所在的政策做一下标记,然后让ip2所在的政策有没有在这些标记中的即可。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 33005;
typedef long long ll;
int Q;
bool vis[1055];
int mark[1055];
int ch[maxn][2], n = 1;
vector <int> val[maxn];
void insert(ll ip, int len, int id) {
int p = 0;
for(int i = 31; i >= 32 - len; i--) {
int k = (ip >> i) & 1;
if(!ch[p][k])
ch[p][k] = n++;
p = ch[p][k];
}
val[p].push_back(id);
}
void color(ll ip) {
int p = 0;
for(int i = 31; i >= 0; i--) {
int k = (ip >> i) & 1;
if(!ch[p][k]) return;
p = ch[p][k];
for(int j = 0; j < val[p].size(); j++)
if(vis[val[p][j]])
mark[val[p][j]] = Q;
}
}
bool judge(ll ip) {
int p = 0;
for(int i = 31; i >= 0; i--) {
int k = (ip >> i) & 1;
if(!ch[p][k]) return false;
p = ch[p][k];
for(int j = 0; j < val[p].size(); j++) {
if(mark[val[p][j]] == Q)
return true;
}
}
return false;
}
ll getIp(int a, int b, int c, int d) {
ll ret = 0;
ret |= (ll) a << 24;
ret |= (ll) b << 16;
ret |= (ll) c << 8;
ret |= d;
return ret;
}
char op[3];
int a, b, c, d, e, id;
int main() {
while(~scanf("%s", op)) {
if(op[0] == 'E') {
int n;
scanf("%d%d", &id, &n);
while(n--) {
scanf("%d.%d.%d.%d/%d", &a, &b, &c, &d, &e);
insert(getIp(a, b, c, d), e, id);
}
vis[id] = 1;
}
if(op[0] == 'D') {
scanf("%d", &id);
vis[id] = 0;
}
if(op[0] == 'F') {
Q++;
scanf("%d.%d.%d.%d", &a, &b, &c, &d);
color(getIp(a, b, c, d));
scanf("%d.%d.%d.%d", &a, &b, &c, &d);
puts( judge(getIp(a, b, c, d))? "F" : "D");
}
}
return 0;
}