【Trie】[CQOI2016]路由表

题目描述

【Trie】[CQOI2016]路由表_第1张图片

对于一次查询的一种理解方式是:无视其它所有查询操作,只看添加操作。先清空路由表,然后执行第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();
}

你可能感兴趣的:(C++,字符串,trie,CQOI,省选)