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\n",ans);
158         }
159     }
160     return 0;
161 }

原文地址:https://www.cnblogs.com/lnxcj/p/10021072.html

时间: 2024-08-05 12:48:16

bzoj[3881]Divljak(dfs序+树状数组+fail树)的相关文章

【BZOJ】1146: [CTSC2008]网络管理Network(树链剖分+线段树套平衡树+二分 / dfs序+树状数组+主席树)

第一种做法(时间太感人): 这题我真的逗了,调了一下午,疯狂造数据,始终找不到错. 后来发现自己sb了,更新那里没有打id,直接套上u了.我.... 调了一下午啊!一下午的时光啊!本来说好中午A掉去学习第二种做法,噗 好吧,现在第一种做法是hld+seg+bst+二分,常数巨大,log^4级别,目前只会这种. 树剖后仍然用线段树维护dfs序区间,然后在每个区间建一颗平衡树,我用treap,(这题找最大啊,,,囧,并且要注意,这里的rank是比他大的数量,so,我们在二分时判断要判断一个范围,即要

【bzoj1146】[CTSC2008]网络管理Network 倍增LCA+dfs序+树状数组+主席树

题目描述 M公司是一个非常庞大的跨国公司,在许多国家都设有它的下属分支机构或部门.为了让分布在世界各地的N个部门之间协同工作,公司搭建了一个连接整个公司的通信网络.该网络的结构由N个路由器和N-1条高速光缆组成.每个部门都有一个专属的路由器,部门局域网内的所有机器都联向这个路由器,然后再通过这个通信子网与其他部门进行通信联络.该网络结构保证网络中的任意两个路由器之间都存在一条直接或间接路径以进行通信. 高速光缆的数据传输速度非常快,以至于利用光缆传输的延迟时间可以忽略.但是由于路由器老化,在这些

【BZOJ】1047: [HAOI2007]理想的正方形(单调队列/~二维rmq+树状数组套树状数组)

http://www.lydsy.com/JudgeOnline/problem.php?id=1047 树状数组套树状数组真心没用QAQ....首先它不能修改..而不修改的可以用单调队列做掉,而且更快,只有O(n^2).而这货是n^2log^2n的建树...虽然查询是log^2n...但是建树那里就tle了.. 那么说题解... 先orz下,好神.. 我怎么没想到单调队列orz 首先我们维护 行 的单调队列,更新每个点在 列 距离内的最小and最大的值 然后我们维护 列 的单调队列,更新每个点

【bzoj3744】Gty的妹子序列 分块+树状数组+主席树

题目描述 我早已习惯你不在身边, 人间四月天 寂寞断了弦. 回望身后蓝天, 跟再见说再见…… 某天,蒟蒻Autumn发现了从 Gty的妹子树(bzoj3720) 上掉落下来了许多妹子,他发现 她们排成了一个序列,每个妹子有一个美丽度. Bakser神犇与他打算研究一下这个妹子序列,于是Bakser神犇问道:"你知道区间 [l,r]中妹子们美丽度的逆序对数吗?" 蒟蒻Autumn只会离线乱搞啊……但是Bakser神犇说道:"强制在线." 请你帮助一下Autumn吧.

hdu1394(枚举/树状数组/线段树单点更新&amp;区间求和)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394 题意:给出一个循环数组,求其逆序对最少为多少: 思路:对于逆序对: 交换两个相邻数,逆序数 +1 或 -1, 交换两个不相邻数 a, b, 逆序数 += 两者间大于 a 的个数 - 两者间小于 a 的个数: 所以只要求出初始时的逆序对数,就可以推出其余情况时的逆序对数.对于求初始逆序对数,这里 n 只有 5e3,可以直接暴力 / 树状数组 / 线段树 / 归并排序: 代码: 1.直接暴力 1

hdu 1166 树状数组 线段树

敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 51177    Accepted Submission(s): 21427 Problem Description C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务

【BZOJ-1452】Count 树状数组 套 树状数组

1452: [JSOI2009]Count Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1769  Solved: 1059[Submit][Status][Discuss] Description Input Output Sample Input Sample Output 1 2 HINT Source Solution 忽略标题的说法...撞壁用的.... 简单题,裸树状数组套树状数组 颜色数目$c<=100$很小,考虑对于每种颜色单独进

HDU 1394 Minimum Inversion Number 树状数组&amp;&amp;线段树

题目给了你一串序列,然后每次 把最后一个数提到最前面来,直到原来的第一个数到了最后一个,每次操作都会产生一个新的序列,这个序列具有一个逆序数的值,问最小的你逆序数的值为多少 逆序数么 最好想到的是树状数组,敲了一把很快,注意把握把最后一个数提上来对逆序数的影响即可, #include<iostream> #include<cstdio> #include<list> #include<algorithm> #include<cstring> #i

HDU 1166 敌兵布阵 (树状数组&#183;线段树)

题意  中文 动态区间和问题   只会更新点  最基础的树状数组 线段树的应用 树状数组代码 #include <bits/stdc++.h> using namespace std; const int N = 50005; int c[N], n, m; void add(int p, int x) { while(p <= n) c[p] += x, p += p & -p; } int getSum(int p) { int ret = 0; while(p > 0