数据保证无相同有效地址(地址中掩码部分)出现
对于一次查询的一种理解方式是:无视其它所有查询操作,只看添加操作。先清空路由表,然后执行第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; }