bzoj 4523 [Cqoi2016]路由表

Trie树的运用。

对于A操作,将IP地址转为2进制串后插入Trie树中,在结束节点增加时间标记。

对于Q操作,将IP地址转为2进制串后在Trie树中匹配。

在匹配过程中,用单调栈维护时间单调递增。栈的大小就是答案。

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
typedef long long LL;
struct Trie{int ch[2],ti;}t[35000005];//memory?? 400MB
int bh=0,rt=0,tt=0,stk[2000005],xbj;
void Insert(int &x,LL num,int dep,int len)
{   if(!x){x=++bh;t[x]=t[0];}
    if(!len){t[x].ti=tt;return;}//在结束节点打上时间标记
    int p=int((num>>(dep-1))&1);
    Insert(t[x].ch[p],num,dep-1,len-1);
}
int Query(int x,int L,int R,LL num,int dep)//随着匹配的进行,匹配长度在不断增加
{   if(t[x].ti)
      {if(t[x].ti<L)stk[0]=0;//时间在询问区间之前,则清空栈
       if(L<=t[x].ti&&t[x].ti<=R)//时间在询问区间中,则维护时间单调递增
         {while(stk[0]&&stk[stk[0]]>t[x].ti)stk[0]--;
          stk[++stk[0]]=t[x].ti;
         }
      }
    if(!dep)return stk[0];
    int p=int((num>>(dep-1))&1);
    return Query(t[x].ch[p],L,R,num,dep-1);
}
int main()
{   int i,N,e,L,R,ans;
    LL a,b,c,d;
    char s[10];
    t[0].ch[0]=t[0].ch[1]=t[0].ti=0;
    scanf("%d",&N);
    for(i=1;i<=N;i++)
      {scanf("%s",s+1);
       if(s[1]=='A')
         {scanf("%lld.%lld.%lld.%lld/%d",&a,&b,&c,&d,&e);
          tt++;
          Insert(rt,(a<<24LL)+(b<<16LL)+(c<<8LL)+d,32,e);
         }
       else if(s[1]=='Q')
         {scanf("%lld.%lld.%lld.%lld",&a,&b,&c,&d);
          scanf("%d%d",&L,&R);
          stk[0]=0;
          printf("%d\n",Query(rt,L,R,(a<<24LL)+(b<<16LL)+(c<<8LL)+d,32));
         }
      }
    return 0;
}


你可能感兴趣的:(bzoj 4523 [Cqoi2016]路由表)