题目大意:有多个政策,每个政策里面有很多子网,E 表示加入一个政策,D表示禁止一个政策,F就是询问ip1,ip2是不是在同一个政策中。
思路:子网有个特点前缀相同,对于E操作,不难想到用字典树来维护所有子网(即ip的前缀),每个节点用一个vector保存该子网(即前缀)所属于的所有政策的标号。对于D操作,我们用一个数组维护该政策可不可用,对于F就是先把ip1所在的政策做一下标记,然后让ip2所在的政策有没有在这些标记中的即可。
//#pragma comment(linker, "/STACK:102400000") #include<cstdlib> #include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #include<set> #include<map> #include<list> #include<queue> #include<vector> #define tree int o,int l,int r #define lson o<<1,l,mid #define rson o<<1|1,mid+1,r #define lo o<<1 #define ro o<<1|1 #define pb push_back #define mp make_pair #define ULL unsigned long long #define LL long long #define inf 0x7fffffff #define eps 1e-7 #define N 109 using namespace std; int m,n,T,t; char str[10]; int ch[800000][2],sz,id,len,ncase; vector<int> g[800000]; int vis[1125],f[1125]; void init() { sz=1; memset(ch[0],0,sizeof(ch[0])); } LL readip() { int a,b,c,d; scanf("%d.%d.%d.%d",&a,&b,&c,&d); LL ans=0; ans+=a;ans<<=8; ans+=b;ans<<=8; ans+=c;ans<<=8; ans+=d; return ans; } void insert(LL ip,int len,int id) { int u=0; for(int i=31,j=0;j<len;j++,i--) { int c=(ip>>i)&1; if(ch[u][c]==0) { ch[u][c]=sz++; } u=ch[u][c]; } g[u].push_back(id); } void fun(LL ip) { int u=0; for(int i=31;i>=0;i--) { int c=(ip>>i)&1; if(ch[u][c]==0) { break; } u=ch[u][c]; for(int j=0;j<g[u].size();j++) if(vis[g[u][j]]) f[g[u][j]]=ncase; } } int solve(LL ip) { int u=0; for(int i=31;i>=0;i--) { int c=(ip>>i)&1; if(ch[u][c]==0) { break; } u=ch[u][c]; for(int j=0;j<g[u].size();j++) if(vis[g[u][j]]&&f[g[u][j]]==ncase) return 1; } return 0; } int main() { #ifndef ONLINE_JUDGE freopen("ex.in","r",stdin); #endif init(); while(scanf("%s",str)==1) { if(str[0]=='E') { scanf("%d%d",&id,&n); vis[id]=1; for (int i=0;i<n;++i ) { LL ip=readip(); scanf("/%d",&len); insert(ip,len,id); } } else if(str[0]=='D') { scanf("%d",&id); vis[id]=0; } else { ncase++; LL ip1=readip(); LL ip2=readip(); fun(ip1); puts(solve(ip2)?"F":"D"); } } return 0; }