• BZOJ5084: hashit


    (很神仙的题啊  爆栈了 手动扩栈才过

    题解:我们考虑题目实质上形成一颗trie树 查询的是trie树上每个节点到根路径上形成的字符串的子串中不同子串的个数 我们考虑每个点的价值=父亲节点的价值+这个点后缀不同子串的个数 那么我们建广义的后缀自动机在trie树上转移 然后查询当前节点在parent树中到根链的并集即可 那么我们考虑用set来维护树链的并 然后统计答案即可

    #pragma comment(linker, "/STACK:102400000,102400000")
    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <vector>
    #include <stack>
    #include <queue>
    #include <cmath>
    #include <set>
    #include <map>
    #define mp make_pair
    #define pb push_back
    #define pii pair<int,int>
    #define link(x) for(edge *j=h[x];j;j=j->next)
    #define inc(i,l,r) for(int i=l;i<=r;i++)
    #define dec(i,r,l) for(int i=r;i>=l;i--)
    const int MAXN=2e5+10;
    const double eps=1e-8;
    #define ll long long
    using namespace std;
    // int size = 256 << 20; // 256MB  
    // char *pp = (char*)malloc(size) + size;  
    // __asm__("movl %0, %%esp
    " :: "r"(pp));
    struct edge{int t;edge*next;}e[MAXN<<1],*h[MAXN<<1],*o=e;
    void add(int x,int y){o->t=y;o->next=h[x];h[x]=o++;}
    ll read(){
        ll x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    typedef struct node{
        int f,a[26];
        vector<int>vec;
    }node;
    node d[MAXN];
    int rt,cnt;char str[MAXN];
    void newnode(int &x,int pre){
        x=++cnt;d[x].vec.clear();d[x].f=pre;
        for(int i=0;i<26;i++)d[x].a[i]=0;
    }
    int cur,rt1,dis[MAXN<<1],fa[MAXN<<1][21],cnt1,ch[MAXN<<1][26],dep[MAXN<<1];
    int pos[MAXN];
    ll dist[MAXN<<1],ans[MAXN];
    int built(int x){
        int last=cur;cur=++cnt1;dis[cur]=dis[last]+1;int pp=last;
        for(;pp&&!ch[pp][x];pp=fa[pp][0])ch[pp][x]=cur;
        if(!pp)fa[cur][0]=rt1;
        else{
            int q=ch[pp][x];
            if(dis[q]==dis[pp]+1)fa[cur][0]=q;
            else{
                int nt=++cnt1;dis[nt]=dis[pp]+1;
                memcpy(ch[nt],ch[q],sizeof(ch[q]));
                fa[nt][0]=fa[q][0];fa[q][0]=fa[cur][0]=nt;
                for(;ch[pp][x]==q;pp=fa[pp][0])ch[pp][x]=nt;
            }
        }
        return cur;
    }
    void dfs(int x){
        for(int i=0;i<26;i++){
            if(!d[x].a[i])continue;
            cur=pos[x];pos[d[x].a[i]]=built(i);
            dfs(d[x].a[i]);
        }
    }
    int p[MAXN<<1],fp[MAXN<<1],cnt2;
    set<int>s;
    set<int>::iterator ite,ip;
    void dfs1(int x,int deep){
        dep[x]=deep+1;p[x]=++cnt2;fp[p[x]]=x;
        for(int i=1;i<=20;i++)fa[x][i]=fa[fa[x][i-1]][i-1];
        link(x){
            dist[j->t]=dist[x]+dis[j->t]-dis[x];
            dfs1(j->t,deep+1);
        }
    }
    int Lca(int u,int v){
        if(dep[u]<dep[v])swap(u,v);
        int tmp=dep[u]-dep[v];
        for(int i=0;i<=20;i++)if(tmp&(1<<i))u=fa[u][i];
        if(u==v) return u;
        for(int i=20;i>=0;i--){
            if(fa[u][i]!=fa[v][i])u=fa[u][i],v=fa[v][i];
        }
        return fa[u][0];
    }
    void solve(int x,ll ans1){
        for(int i=0;i<26;i++){
            if(!d[x].a[i])continue;
            int xx=0,yy=0;ll t=ans1;
            ite=s.lower_bound(p[pos[d[x].a[i]]]);
            //printf("%d=====
    ",s.size());
            t+=dist[pos[d[x].a[i]]];
            if(ite!=s.begin())ip=ite,ip--,xx=fp[(*ip)],t-=dist[Lca(xx,pos[d[x].a[i]])];
            if(ite!=s.end())ip=ite,yy=fp[(*ip)],t-=dist[Lca(yy,pos[d[x].a[i]])];
            if(xx&&yy)t+=dist[Lca(xx,yy)];
            for(int j=0;j<d[d[x].a[i]].vec.size();j++)ans[d[d[x].a[i]].vec[j]]=t;
            s.insert(p[pos[d[x].a[i]]]);
            solve(d[x].a[i],t);
        }
        s.erase(p[pos[x]]);
    }
    int main(){
        rt=cnt=0;cnt1=0;cnt2=0;
        scanf("%s",str+1);int len=strlen(str+1);newnode(rt,0);
        int temp=rt;
        for(int i=1;i<=len;i++){
            if(str[i]=='-')temp=d[temp].f,d[temp].vec.pb(i);
            else{
                int t=str[i]-'a';
                if(!d[temp].a[t]) newnode(d[temp].a[t],temp);
                temp=d[temp].a[t];
                d[temp].vec.pb(i);
            }
        }
        //cout<<cnt<<endl;
        //cout<<"sb"<<endl;
        pos[rt]=1;cnt1=rt1=1;dfs(rt);
        //cout<<cnt1<<endl;
        //cout<<"sb"<<endl;
        for(int i=1;i<=cnt1;i++)add(fa[i][0],i);
        dfs1(rt1,0);
        //cout<<"sb"<<endl;
        solve(rt,0);
        //for(int i=1;i<=len;i++)
        for(int i=1;i<=len;i++)printf("%lld
    ",ans[i]);
    }
    

     

    5084: hashit

    Time Limit: 20 Sec  Memory Limit: 256 MB
    Submit: 223  Solved: 94
    [Submit][Status][Discuss]

    Description

    你有一个字符串S,一开始为空串,要求支持两种操作
    在S后面加入字母C
    删除S最后一个字母
    问每次操作后S有多少个两两不同的连续子串
     
     
     

    Input

    一行一个字符串Q,表示对S的操作
    如果第i个字母是小写字母c,表示第一种加字母c的操作
    如果为-表示删除操作,保证所有删除操作前S都非空
    |Q|<=10^5
     
     
     

    Output

    输出|Q|行,第i行表示i个操作之后S内有多少个不同子串
     
     
     

    Sample Input

    aba-caba

    Sample Output

    1
    3
    5
    3
    6
    9
    12
    17

    HINT

     

    Source

  • 相关阅读:
    windows7下检测耳机麦克拔插(转)
    windows实时监测热插拔设备的变化(转)
    Windows ToolTips简要介绍(转)
    c /c++变参函数(转)
    SQL的四种连接查询(转)
    CRichEditCtrl 输入字符串长度限制
    MFC 将 '当前工作路径' 改为 'exe所在路径'(转)
    第5章 文本编程
    第4章 简单绘图
    VC++中有关句柄和指针及其转换(转)
  • 原文地址:https://www.cnblogs.com/wang9897/p/9757189.html
Copyright © 2020-2023  润新知