zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    【Lintcode】112.Remove Duplicates from Sorted List
    【Lintcode】087.Remove Node in Binary Search Tree
    【Lintcode】011.Search Range in Binary Search Tree
    【Lintcode】095.Validate Binary Search Tree
    【Lintcode】069.Binary Tree Level Order Traversal
    【Lintcode】088.Lowest Common Ancestor
    【Lintcode】094.Binary Tree Maximum Path Sum
    【算法总结】二叉树
    库(静态库和动态库)
    从尾到头打印链表
  • 原文地址:https://www.cnblogs.com/wang9897/p/9757189.html
Copyright © 2011-2022 走看看