• 【BZOJ3881】【COCI2015】Divljak


    这题原本xsy上有且暴力可过。。。结果考场上加了hack数据并且开了subtask。。。myh:你们乖乖写正解吧

    (正解代码交回去反而更慢了QAQ)

    题意:

    Description

    Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的。
    接下来会发生q个操作,操作有两种形式:
    “1 P”,Bob往自己的集合里添加了一个字符串P。
    “2 x”,Alice询问Bob,集合T中有多少个字符串包含串S_x。(我们称串A包含串B,当且仅当B是A的子串)
    Bob遇到了困难,需要你的帮助。

    Input

    第1行,一个数n;
    接下来n行,每行一个字符串表示S_i;
    下一行,一个数q;
    接下来q行,每行一个操作,格式见题目描述。
    1 <= n,q <= 100000;
    Alice和Bob拥有的字符串长度之和各自都不会超过 2000000;
    字符串都由小写英文字母组成。

    Output

    对于每一个Alice的询问,帮Bob输出答案

    题解:

    先对S建出AC自动机;

    暴力就是每次加入一个T就对所有经过的节点沿着fail指针暴力跳然后修改,但这样会被构造卡成$O(n^2)$的;

    正解就是建出fail树,然后每次修改就是把几条树链的并的节点全部加一,那么排序一下,在每个节点处加一,然后在相邻节点减一(注意去重且不包括第一个)即可;

    使用树状数组解决。

    听说倍增LCA会被卡?实测并不会。。。

    代码:

      1 #include<algorithm>
      2 #include<iostream>
      3 #include<cstring>
      4 #include<cstdio>
      5 #include<vector>
      6 #include<cmath>
      7 #include<queue>
      8 #define inf 2147483647
      9 #define eps 1e-9
     10 #define lb(x) (x&-x)
     11 using namespace std;
     12 typedef long long ll;
     13 struct node{
     14     int son[26],fail;
     15     node(){
     16         memset(son,0,sizeof(son));
     17         fail=0;
     18     }
     19 }t[2000001];
     20 struct edge{
     21     int v,next;
     22 }a[2000001];
     23 int n,Q,x,y,cnt=0,tot=0,tim=0,tr[5000001],ed[2000001],head[2000001],in[2000001],out[2000001],nmd[2000001],ans[2000001],fa[2000001][22],dep[2000001];
     24 char s[1000001];
     25 void add(int u,int v){
     26     a[++tot].v=v;
     27     a[tot].next=head[u];
     28     head[u]=tot;
     29 }
     30 void _add(int u,int x){
     31     for(;u<=cnt+1;u+=lb(u)){
     32         tr[u]+=x;
     33     }
     34 }
     35 int query(int u){
     36     int ret=0;
     37     for(;u;u-=lb(u)){
     38         ret+=tr[u];
     39     }
     40     return ret;
     41 }
     42 void ins(char s[],int x){
     43     int len=strlen(s),now=0;
     44     for(int i=0;i<len;i++){
     45         if(!t[now].son[s[i]-'a'])t[now].son[s[i]-'a']=++cnt;
     46         now=t[now].son[s[i]-'a'];
     47     }
     48     ed[x]=now+1;
     49 }
     50 void AC(){
     51     queue<int>q;
     52     for(int i=0;i<26;i++){
     53         if(t[0].son[i]){
     54             add(1,t[0].son[i]+1);
     55             t[t[0].son[i]].fail=0;
     56             q.push(t[0].son[i]);
     57         }
     58     }
     59     while(!q.empty()){
     60         int u=q.front();
     61         q.pop();
     62         for(int i=0;i<26;i++){
     63             if(t[u].son[i]){
     64                 t[t[u].son[i]].fail=t[t[u].fail].son[i];
     65                 add(t[t[u].son[i]].fail+1,t[u].son[i]+1);
     66                 q.push(t[u].son[i]);
     67             }else t[u].son[i]=t[t[u].fail].son[i];
     68         }
     69     }
     70 }
     71 void dfs(int u,int ff,int dpt){
     72     in[u]=++tim;
     73     nmd[tim]=u;
     74     dep[u]=dpt;
     75     fa[u][0]=ff;
     76     for(int i=1;i<=21;i++)fa[u][i]=fa[fa[u][i-1]][i-1];
     77     for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){
     78         int v=a[tmp].v;
     79         dfs(v,u,dpt+1);
     80     }
     81     out[u]=tim;
     82 }
     83 int lca(int u,int v){
     84     if(dep[u]<dep[v])swap(u,v);
     85     int l=dep[u]-dep[v];
     86     for(int i=21;i>=0;i--){
     87         if((1<<i)&l){
     88             u=fa[u][i];
     89         }
     90     }
     91     if(u==v)return u;
     92     for(int i=21;i>=0;i--){
     93         if(fa[u][i]!=fa[v][i]){
     94             u=fa[u][i],v=fa[v][i];
     95         }
     96     }
     97     return fa[u][0];
     98 }
     99 void work(char s[]){
    100     int len=strlen(s),now=0;
    101     vector<int>p;
    102     for(int i=0;i<len;i++){
    103         now=t[now].son[s[i]-'a'];
    104         p.push_back(in[now+1]);
    105     }
    106     sort(p.begin(),p.end());
    107     p.erase(unique(p.begin(),p.end()),p.end());
    108     for(int i=0,ii=p.size();i<ii;i++){
    109         _add(p[i],1);
    110         if(i)_add(in[lca(nmd[p[i]],nmd[p[i-1]])],-1);
    111     }
    112 }
    113 int main(){
    114     memset(head,-1,sizeof(head));
    115     scanf("%d%d",&n,&Q);
    116     for(int i=1;i<=n;i++){
    117         scanf("%s",s);
    118         ins(s,i);
    119     }
    120     AC();
    121     dfs(1,0,1);
    122     scanf("%d",&Q);
    123     for(int q=1;q<=Q;q++){
    124         scanf("%d",&x);
    125         if(x==1){
    126             scanf("%s",s);
    127             work(s);
    128         }else{
    129             scanf("%d",&y);
    130             //printf("%d %d %d
    ",ed[y],in[ed[y]],out[ed[y]]);
    131             printf("%d
    ",query(out[ed[y]])-query(in[ed[y]]-1));
    132         }
    133     } 
    134     return 0;
    135 }
  • 相关阅读:
    哈希算法是怎么实现的
    高并发下日志组件的各种实现方式
    算法是如何影响程序编码方式的
    <<.NET B/S 架构实践>> 几种概念区别
    如何扩大系统盘空间
    区别:ASP.NET MVC的Model、DTO、Command
    能递归检查DataAnnotations的验证函数
    NuGet的本地服务器安装与Package的发布(呕吐)
    多模块分布式系统的简单服务访问
    多模块后带来的问题解决方法
  • 原文地址:https://www.cnblogs.com/dcdcbigbig/p/9846389.html
Copyright © 2020-2023  润新知