[BZOJ 4523] [CQOI2016]路由表(Trie+单调栈)

[BZOJ 4523] [CQOI2016]路由表(Trie+单调栈)

题面

题面过长,略。

分析

对于添加的每个路由表,我们只把掩码那么长的前缀加入01Trie,然后在结尾位置标记插入时间.

查询时我们先找到查询地址在Trie上对应的一条路径。对于路径上的两个串结尾(x,y),若(x)(y)的祖先,且(x)的插入时间比(y)晚,那么(x)存在的时候更长的(y)也存在,那么永远不会选择到(x). 因此我们可以维护一个单调栈,每次碰到一个串结尾就把时间加入,然后弹出更大的元素。最后栈里面留下的元素都是被选择过的串的插入时间,在([l,r])范围内的元素的个数即为答案。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<stack>
#define maxn 1000000
#define INF 0x3f3f3f3f
using namespace std;
int m;

struct Trie{
	int sz;
	int ch[maxn*32+5][2];
	int val[maxn*32+5];
	void insert(unsigned int v,int len,int tim){
		int x=0; 
		for(int i=31,j=1;j<=len;i--,j++){
			int c=(v>>i)&1;
			if(!ch[x][c]) ch[x][c]=++sz;
			x=ch[x][c];
		} 
		val[x]=tim;
	}
	int query(unsigned int v,int l,int r){
		stack<int>stk;
		int x=0; 
		for(int i=31;i>=0;i--){
			int c=(v>>i)&1;
			if(val[x]){
				while(!stk.empty()&&stk.top()>val[x]) stk.pop();
				stk.push(val[x]);
			}
			if(!ch[x][c]) break;
			x=ch[x][c];
		}
		int ans=0;
		int mint=INF;
		while(!stk.empty()){
			int t=stk.top();
			if(t>=l&&t<=r) ans++;
			stk.pop();
		}
		return ans;
	}
}T;
int main(){
	char cmd[2];
	scanf("%d",&m);
	int tim=0;
	int len;
	for(int i=1;i<=m;i++){
		scanf("%s",cmd);
		if(cmd[0]=='A'){
			unsigned int x,y,z,w;
			unsigned int ans=0;
			scanf("%d.%d.%d.%d/%d",&x,&y,&z,&w,&len);
			ans=x;
			ans=(ans<<8)+y;
			ans=(ans<<8)+z;
			ans=(ans<<8)+w;
			T.insert(ans,len,++tim);
		}else{
			unsigned int x,y,z,w,l,r;
			unsigned int ans=0;
			scanf("%d.%d.%d.%d",&x,&y,&z,&w);
			ans=x;
			ans=(ans<<8)+y;
			ans=(ans<<8)+z;
			ans=(ans<<8)+w;
			scanf("%d %d",&l,&r);
			printf("%d
",T.query(ans,l,r));
		} 
	}
} 
原文地址:https://www.cnblogs.com/birchtree/p/12219548.html