• bzoj[3881]Divljak(dfs序+树状数组+fail树)


    这道题利用了fail树的神奇性质————父节点为其子节点的前缀

    先对Alice的集合建一个fail树,

    Bob每插入一个串,都将串在自动机上经过的点在树上打上标记(+1)

    每次查询的答案就是询问串的结束节点的子树的贡献

    所以还需要用到树状数组来维护dfs序

    因为Bob的一个串至多只能对Alice的某一个串做出1的贡献,所以不能单纯加和

    要对树链取并

    可以将一个Bob串在fail树上经过的所有点按入栈顺序排序,相邻每两个点的lca贡献-1

    可以证明,这样会使每次某个点的子树内没有重复贡献

      1 #include<queue>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 using namespace std;
      6 int n,m,cnt,tot,tp,num;
      7 char s[2000005];
      8 bool ed[2000005];
      9 int vis[2000005];
     10 int ed_pos[100005];
     11 int head[2000005];
     12 int fa[2000005];
     13 int dep[2000005];
     14 int grand[2000005];
     15 int siz[2000005];
     16 int son[2000005];
     17 int ad[4000005];
     18 int stk[4000005];
     19 int tmp[2000005];
     20 struct Trie{
     21     int son[26];
     22     int fail;
     23 }tr[2000005];
     24 struct Edge{
     25     int fr;
     26     int to;
     27     int nxt;
     28 }edge[2000005];
     29 struct node{
     30     int in;
     31     int out;
     32 }pos[2000005];
     33 int lowbit(int x){
     34     return x&(-x);
     35 }
     36 void init(){
     37     memset(head,-1,sizeof(head));
     38 }
     39 void addx(int x,int v){
     40     while(x<=2*tot){
     41         ad[x]+=v;
     42         x+=lowbit(x);
     43     }
     44 }
     45 int getsum(int x){
     46     int ret=0;
     47     while(x){
     48         ret+=ad[x];
     49         x-=lowbit(x);
     50     }
     51     return ret;
     52 }
     53 void addedge(int u,int v){
     54     edge[cnt].fr=u;
     55     edge[cnt].to=v;
     56     edge[cnt].nxt=head[u];
     57     head[u]=cnt++;
     58 }
     59 void insert(char h[],int mrk){
     60     int now=0;
     61     int len=strlen(h+1);
     62     for(int i=1;i<=len;i++){
     63         int k=h[i]-'a';
     64         if(!tr[now].son[k])tr[now].son[k]=++tot;
     65         now=tr[now].son[k];
     66     }
     67     ed[now]=true;
     68     ed_pos[mrk]=now;
     69 }
     70 void getfail(){
     71     queue<int>que;
     72     for(int i=0;i<26;i++){
     73         if(tr[0].son[i]){
     74             addedge(0,tr[0].son[i]);
     75             que.push(tr[0].son[i]);
     76         }
     77     }
     78     while(!que.empty()){
     79         int u=que.front();
     80         que.pop();
     81         for(int i=0;i<26;i++){
     82             if(tr[u].son[i]){
     83                 tr[tr[u].son[i]].fail=tr[tr[u].fail].son[i];
     84                 addedge(tr[tr[u].fail].son[i],tr[u].son[i]);
     85                 que.push(tr[u].son[i]);
     86             }
     87             else tr[u].son[i]=tr[tr[u].fail].son[i];
     88         }
     89     }
     90 }
     91 void dfs1(int u){
     92     siz[u]=1;stk[++tp]=u;pos[u].in=tp;
     93     for(int i=head[u];i!=-1;i=edge[i].nxt){
     94         int v=edge[i].to;
     95         if(v==fa[u])continue;
     96         fa[v]=u;dep[v]=dep[u]+1;
     97         dfs1(v);siz[u]+=siz[v];
     98         if(siz[v]>siz[son[u]]||(!son[u]))son[u]=v;
     99     }
    100     stk[++tp]=u;pos[u].out=tp;
    101 }
    102 void dfs2(int u){
    103     if(u!=son[fa[u]])grand[u]=u;
    104     else grand[u]=grand[fa[u]];
    105     for(int i=head[u];i!=-1;i=edge[i].nxt){
    106         int v=edge[i].to;
    107         if(v==fa[u])continue;
    108         dfs2(v);
    109     }
    110 }
    111 int lca(int x,int y){
    112     while(grand[x]!=grand[y]){
    113         if(dep[grand[x]]<dep[grand[y]])swap(x,y);
    114         x=fa[grand[x]];
    115     }
    116     if(dep[x]>dep[y])swap(x,y);
    117     return x;
    118 }
    119 int cmp(int a,int b){
    120     return pos[a].in<pos[b].in;
    121 }
    122 void match(char b[],int tim){
    123     int now=0;
    124     int len=strlen(s+1);
    125     for(int i=1;i<=len;i++){
    126         int k=b[i]-'a';
    127         now=tr[now].son[k];
    128         if(vis[now]==tim)continue;
    129         vis[now]=tim;tmp[++num]=now;
    130     }
    131     sort(tmp+1,tmp+num+1,cmp);
    132     for(int i=1;i<=num;i++)addx(pos[tmp[i]].in,1);
    133     for(int i=1;i<num;i++){
    134         int f=lca(tmp[i],tmp[i+1]);
    135         addx(pos[f].in,-1);
    136     }
    137 }
    138 int main(){
    139     init();
    140     scanf("%d",&n);
    141     for(int i=1;i<=n;i++){
    142         scanf("%s",s+1);
    143         insert(s,i);
    144     }
    145     getfail();dfs1(0);dfs2(0);
    146     scanf("%d",&m);
    147     for(int i=1;i<=m;i++){
    148         int ac;
    149         scanf("%d",&ac);
    150         if(ac==1){
    151             scanf("%s",s+1);
    152             num=0;match(s,i);
    153         }else{
    154             int p;
    155             scanf("%d",&p);
    156             int ans=getsum(pos[ed_pos[p]].out)-getsum(pos[ed_pos[p]].in-1);
    157             printf("%d
    ",ans);
    158         }
    159     }
    160     return 0;
    161 }
  • 相关阅读:
    单个 js 文件禁用 ESLint 语法校验
    meta标签整合
    安装es6编译babel
    JSON.parse()和JSON.stringify()的区别
    preventDefault()、stopPropagation()、return false 的区别
    excel 表格内容读取
    redis 小例
    多文件打包下载
    随笔
    js数组删除元素
  • 原文地址:https://www.cnblogs.com/lnxcj/p/10021072.html
Copyright © 2020-2023  润新知