hdu4760Good Firewall(Trie树)

题目链接:点击打开链接

题意描述:现有一个网络中,在不同的子网之间建立转发策略,有相同的转发策略的子网之间可以互相通信

给出以下三种操作:

操作一:E  可以理解为建立标号为id的转发策略,有n个子网,这n个子网之间有相同的转发策略id

操作二:D 取消id这种转发策略

操作三、询问ipsrc与ipdst是否有相同的转发策略(当然一个ip地址可能有多种转发策略)

问题,对于每次询问,如果有相同的转发策略则输出F,否则输出D


解题思路:Trie树

1、一个子网内的IP地址有相同的前缀,其余部分可以任意,所以我们可以根据前缀确定某个ip地址位于哪个子网中(注意:一个ip地址可能位于几个子网中,大子网包含小子网);

2、根据子网前缀建立Trie树,对于Trie中的每个节点对应一个vector保存以当前节点结束的子网有哪些。

3、用vis标记id这种转发策略是否存在

4、mark标记ipsrc位于的转发策略,便于与ipdst对比判断


#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn=33005;
typedef long long ll;
struct Trie{
    int _next[maxn][2],ct;
    bool vis[1055];
    int mark[1055];
    int Q;
    vector<int> val[maxn];
    void init(){
        ct=0;
        Q=1;
        memset(_next,0,sizeof(_next));
        memset(vis,false,sizeof(vis));
        memset(mark,-1,sizeof(mark));
        memset(val,0,sizeof(val));
    }
    void insert(ll ip,int len,int id){
        int rt=0;
        for(int i=31;i>=32-len;i--){
            int k=(ip>>i)&1;
            if(!_next[rt][k])
                _next[rt][k]=++ct;
            rt=_next[rt][k];
        }
        val[rt].push_back(id);
    }
    void color(ll ip){
        int rt=0;
        for(int i=31;i>=0;i--){
            int k=(ip>>i)&1;
            if(!_next[rt][k]) return;
            rt=_next[rt][k];
            int len=val[rt].size();
            for(int j=0;j<len;j++){
                if(vis[val[rt][j]])
                    mark[val[rt][j]]=Q;
            }
        }
    }
    bool judge(ll ip){
        int rt=0;
        for(int i=31;i>=0;i--){
            int k=(ip>>i)&1;
            if(!_next[rt][k]) return false;
            rt=_next[rt][k];
            int len=val[rt].size();
            for(int j=0;j<len;j++)
                if(mark[val[rt][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;
}
int a,b,c,d,e,id;
char op[3];
int main(){
    Trie tr;
    tr.init();
    while(scanf("%s",op)!=EOF){
        if(op[0]=='E'){
            int num;
            scanf("%d%d",&id,&num);
            while(num--){
                scanf("%d.%d.%d.%d/%d",&a,&b,&c,&d,&e);
                tr.insert(getIp(a,b,c,d),e,id);
            }
            tr.vis[id]=1;
        }
        else if(op[0]=='F'){
            tr.Q++;
            scanf("%d.%d.%d.%d",&a,&b,&c,&d);
            tr.color(getIp(a,b,c,d));
            scanf("%d.%d.%d.%d",&a,&b,&c,&d);
            puts(tr.judge(getIp(a,b,c,d))?"F":"D");
        }
        else if(op[0]=='D'){
            scanf("%d",&id);
            tr.vis[id]=0;
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值