hdu4760 字典树 (2013网络赛)

本文介绍了一种使用字典树维护子网策略的算法,针对加入、禁止政策及查询两个IP是否处于同一政策的需求,提供了具体的实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

网络知识比较差,造成看题非常吃力

题目大意:有多个政策,每个政策里面有很多子网,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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值