【Trie】[CQOI2016]路由表
2016-04-10 21:19
435 查看
题目描述
对于一次查询的一种理解方式是:无视其它所有查询操作,只看添加操作。先清空路由表,然后执行第1到a-1次添加操作。之后再执行第a到b次添加操作过程中,统计匹配改变的次数。
数据范围:
设一条表项的掩码长度为L,数据保证将目的地址转为二进制串后,末尾的32-L位均为0。
分析
在线地,每次在添加表项至路由表的时候,将该地址加入trie,然后在结束的节点标记上添加这个表项的时间。对于每次询问,在trie上暴力匹配,然后用一个单调栈,使得能够匹配的表项出现的时间随着长度的增加而增加,最后通过二分查找找到在a,b之间改变了多少次即可。
代码
#include<cstdio> #include<algorithm> #define MAXN 1000000 #define INF 0xffffffffu using namespace std; typedef unsigned int uint; int n,cnt; struct query{ uint c; int len; inline query(){ } inline query(uint c,int len):c(c),len(len){ } }q[MAXN+10]; struct node{ int pos; int ch[2]; }tree[MAXN*32+10],*root=tree,*tcnt=tree; template<class T> void Read(T &x){ char c; while(c=getchar(),c!=EOF) if(c>='0'&&c<='9'){ x=c-'0'; while(c=getchar(),c>='0'&&c<='9') x=x*10+c-'0'; ungetc(c,stdin); return; } } void read(){ Read(n); } void solve(){ char s[20]; uint c,t; int len,i,a,b,best,ans; while(n--){ scanf("%s",s); if(s[0]=='A'){ c=a=0; Read(a); c=(c<<8)+a; Read(a); c=(c<<8)+a; Read(a); c=(c<<8)+a; Read(a); c=(c<<8)+a; Read(len); q[++cnt]=query(c,len); } else{ c=a=ans=0; Read(a); c=(c<<8)+a; Read(a); c=(c<<8)+a; Read(a); c=(c<<8)+a; Read(a); c=(c<<8)+a; Read(a),Read(b); best=0; for(i=1;i<a;i++){ t=INF^((1ll<<(32-q[i].len))-1); if(q[i].c==(c&t)) if(q[i].len>q[best].len) best=i; } for(;i<=b;i++){ t=INF^((1ll<<(32-q[i].len))-1); if(q[i].c==(c&t)) if(q[i].len>q[best].len) best=i,ans++; } printf("%d\n",ans); } } } int s[MAXN+10],tp; void solve2(){ char ss[20]; int a,b,len,i,x[40],pos,ans; uint c; bool d; node *p; while(n--){ scanf("%s",ss); if(ss[0]=='A'){ c=0; Read(a); c=(c<<8)+a; Read(a); c=(c<<8)+a; Read(a); c=(c<<8)+a; Read(a); c=(c<<8)+a; Read(len); p=root; for(i=31;i>=32-len;i--){ d=(c>>i)&1; if(!p->ch[d]) p->ch[d]=++tcnt-tree; p=tree+p->ch[d]; } p->pos=++cnt; } else{ len=0; Read(a); for(i=7;i>=0;i--) x[++len]=(a>>i)&1; Read(a); for(i=7;i>=0;i--) x[++len]=(a>>i)&1; Read(a); for(i=7;i>=0;i--) x[++len]=(a>>i)&1; Read(a); for(i=7;i>=0;i--) x[++len]=(a>>i)&1; Read(a),Read(b); tp=0; p=root; for(i=1;i<=32;i++){ if(p->ch[x[i]]) p=tree+p->ch[x[i]]; else break; if(p->pos&&p->pos<=b){ pos=p->pos; while(tp>0&&s[tp]>pos) tp--; s[++tp]=pos; } } ans=tp-(lower_bound(s+1,s+tp+1,a)-s)+1; printf("%d\n",ans); } } } int main() { read(); if(n<=1000) solve(); else solve2(); }
相关文章推荐
- samba服务器搭建
- 如何用netstat命令查看端口占用问题的技巧
- [架构]我眼中的Android架构
- Android学习(19) -- 数据存储之File (简单登录保存用户名和密码)
- sizeof()用法汇总
- Java NIO系列教程(二) Channel
- Servlet技术
- atitit.React 优缺点 相比angular react是最靠谱的web ui组件化方案了
- 019.php函数变量
- java中对象的比较
- UBUNTU 修改网卡名称 更改设备网卡名称 修改ENO16777736为ETH0 UBUNTU 15.10网卡名称为ENO16777736(http://www.cnphp6.com/archiv)
- atitit.React 优缺点 相比angular react是最靠谱的web ui组件化方案了
- 四则运算安卓
- DotNet 资源大全
- 架构高性能网站秘笈(一)——了解衡量网站性能的指标
- hdu 1016 Prime Ring Problem(dfs)
- yii 查询构建器
- CAS 数据库校验
- Hibernate单向关联比较
- Caused by: java.lang.ClassNotFoundException: org.hibernate.annotations.Entity