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\n" :: "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=====\n",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\n",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

posted @ 2018-10-08 21:10  wang9897  阅读(150)  评论(0编辑  收藏  举报