您的位置:首页 > 其它

【BZOJ4523】【CQOI2016】路由表 Trie

2016-04-12 23:00 405 查看




数据保证无相同有效地址(地址中掩码部分)出现

对于一次查询的一种理解方式是:无视其它所有查询操作,只看添加操作。先清空路由表,然后执行第1到a-1次添加操作。之后再执行第a到b次添加操作过程中,统计匹配改变的次数。

第一眼扫过去是可持久,<del>但是转念一想去年CQOI考过这东西果断跳过<del>

<del>这题对拍数据之难做hhh<del>

这年头输入都不按套路来。。。间接考察了一波输入优化

思路比较清晰,插入的地址的有效部分甩进一棵Trie,末尾节点的值标记为插入时间,不难想到搜索时改变匹配项的条件是:沿着trie一路找下去,出现插入时间更靠后的项。

因此我们在沿着trie查找时维护一个栈,无视时间大于B的操作,保证栈内的插入时间递增,找完之后在定位小于a的最后一项。栈内大于a的元素个数就是改变的次数。

(这题开100000*40的数组就能A这种事我是不会说的)

#include<cstdlib>
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
#define maxn 1000005
int np,rt,chi[maxn*35][2],val[maxn*35];
int n,L;
int s[40];
void _read(int &x)
{
x=0;
char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0' && ch<='9')
{
x=x*10+ch-'0'; ch=getchar();
}
return ;
}
void getIP()
{
int cnt=0,x;
for(int i=1;i<=4;i++)
{
_read(x);
for(int j=7;j>=0;j--)
{
s[++cnt]=(1&(x>>j));
}
}
return ;
}
void Insert(int time)
{
int now=rt,d;
for(int i=1;i<=L;i++)
{
d=s[i];
if(!chi[now][d])
{
chi[now][d]=++np;chi[np][0]=chi[np][1]=0;val[np]=0;
}
now=chi[now][d];
}
val[now]=time;
return ;
}
int st[40],top;
void query(int a,int b)
{
top=0;
int d,t,now=rt;
for(int i=1;i<=32;i++)
{
d=s[i];
if(!chi[now][d])break;
now=chi[now][d];
if(val[now])
{
t=val[now];
if(t>b)continue;
while(top>0 && st[top]>t)
{
top--;
}
st[++top]=t;
}
}
int c=0;
while(c<top && st[c+1]<a)c++;
printf("%d\n",top-c);
return ;
}
void work()
{
int cnt=0,x,y;
char op;
np=rt=1;chi[0][0]=chi[1][0]=chi[0][1]=chi[1][1]=0;
val[0]=val[1]=0;
scanf("%d",&n);
int woc=0;
for(int i=1;i<=n;i++)
{
op=getchar();
while(op!='A' && op!='Q')
{
op=getchar();
}
if(op=='A')
{
cnt++;
getIP();_read(L);
Insert(cnt);
}
else
{
woc++;
getIP();_read(x); _read(y);
query(x,y);
}
//cout<<i<<endl;
}
return ;
}
int main()
{
//freopen("route.in","r",stdin);
//freopen("route.out","w",stdout);

work();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: