【BZOJ4523】【CQOI2016】路由表 Trie

【BZOJ4523】【CQOI2016】路由表 Trie_第1张图片【BZOJ4523】【CQOI2016】路由表 Trie_第2张图片

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

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

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

这题对拍数据之难做hhh

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

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

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

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

#include
#include
#include
#include
#include
#include
#include
#include
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


你可能感兴趣的:(Trie)