【uva1502/hdu4117-GRE Words】DP+线段树优化+AC自动机
这题我的代码在hdu上AC,在uva上WA。
题意:按顺序输入n个串以及它的权值di,要求在其中选取一些串,前一个必须是后一个的子串。问d值的和最大是多少。 (1≤n≤2×10^4 ,串的总长度<=3*10^5)
题解:
这题一开始我的方向就错了,想了很久d[x][y]表示在AC自动机上的节点x、下一个串要大于y的dp。然而这样做数组要10^4*10^5=10^9级别,开都开不了,妥妥超时。
后来看了一眼题解。。。觉得自己智商真是感人。。。
用f[i]表示以第i个串为结尾的时候最大的d值,这样做就可以知道在AC自动机上的位置、当前在第几个串。
f[i]=max(f[j])+w[i],j所代表的串为i的子串。
现在我们要快速知道子串:
1.
建立AC自动机,然后将fail反向建立fail树。
对于fail树上某个点来说,它的祖先所代表的串必为它的子串(通过一直fail可以到达的点)
fail树上做一遍dfs求出dfn,就可以做到线性时间维护子树的最值。
2.
字符串x在fail树上求到的子串是除了x本身、在其他字符串中求到的子串,但是x自己的某一段也是自己的子串。所以在AC自动机上走到x的末尾节点,所经过的路程每一个点所代表的字符串也是x的子串。
对于每一个i,我把已求出来的f[i]放到failtree上它所对应的点,然后i的整个子树的最大值都要更新一遍。所以我们要开一棵线段树来维护,用failtree的dfn来作为线段树的下标,维护区间最大值。
求f[i]的时候就在AC自动机上走一遍字符串i,对于每个经过的点询问一遍它的值-------解决了第二种子串
询问i的末尾节点的值-----解决了第一种子串,因为在i前面、failtree上是i的祖先的点已经更新了i。
然后取最值,放入failtree上,更新failtree的子树即可。
1 //hdu4117
2
3 #include<cstdio>
4 #include<cstdlib>
5 #include<cstring>
6 #include<iostream>
7 #include<queue>
8 using namespace std;
9
10 const int N=300010,M=20010,S=26;
11 int n,num,cnt_dfn,cnt_seg,len,w[M],last[M],first[N],dfn[N],next_dfn[N];
12 char s[N];
13 struct trie_node{
14 int fa,fail,son[30];
15 }a[N];
16 struct fail_node{
17 int x,y,next;
18 }b[N];
19 struct seg_node{
20 int lc,rc,l,r,d,lazy;
21 }t[2*N];
22 queue<int> q;
23
24 int maxx(int x,int y){return x>y ? x:y;}
25
26 void clear(int x)
27 {
28 a[x].fail=a[x].fa=0;
29 memset(a[x].son,0,sizeof(a[x].son));
30 }
31
32 void ins(int x,int y)
33 {
34 b[++len].x=x;b[len].y=y;
35 b[len].next=first[x];first[x]=len;
36 }
37
38 void read_trie(int id)
39 {
40 scanf("%s%d",s,&w[id]);
41 int x=0,l=strlen(s);
42 for(int i=0;i<l;i++)
43 {
44 // if(!(s[i]>='a' && s[i]<='z')) while(1) ;
45 int ind=s[i]-'a'+1;
46 if(!a[x].son[ind])
47 {
48 num++;
49 clear(num);
50 a[x].son[ind]=num;
51 a[num].fa=x;
52 }
53 x=a[x].son[ind];
54 }
55 last[id]=x;
56 }
57
58 void build_AC_failtree()
59 {
60 while(!q.empty()) q.pop();
61 for(int i=1;i<=S;i++)
62 if(a[0].son[i]) q.push(a[0].son[i]);
63 while(!q.empty())
64 {
65 int x=q.front();q.pop();
66 int fail=a[x].fail;
67 for(int i=1;i<=S;i++)
68 {
69 if(a[x].son[i])
70 {
71 a[a[x].son[i]].fail=a[fail].son[i];
72 q.push(a[x].son[i]);
73 }
74 else a[x].son[i]=a[fail].son[i];
75 }
76 }
77 for(int i=1;i<=num;i++)
78 ins(a[i].fail,i);
79 }
80
81 void make_dfn(int x)
82 {
83 dfn[x]=++cnt_dfn;
84 for(int i=first[x];i;i=b[i].next) make_dfn(b[i].y);
85 next_dfn[x]=cnt_dfn;
86 }
87
88 int build_segtree(int l,int r)
89 {
90 cnt_seg++;
91 int x=cnt_seg;
92 t[x].l=l;t[x].r=r;t[x].d=0;
93 t[x].lc=t[x].rc=0;t[x].lazy=0;//debug 原本根节点是0,但是这里也是0,就WA了
94 if(l!=r)
95 {
96 int mid=(l+r)>>1;
97 t[x].lc=build_segtree(l,mid);
98 t[x].rc=build_segtree(mid+1,r);
99 }
100 return x;
101 }
102
103 void updata(int x)
104 {
105 if(!t[x].lazy) return;
106 int lazy=t[x].lazy,lc=t[x].lc,rc=t[x].rc;
107 t[x].d=maxx(t[x].d,lazy);
108 t[x].lazy=0;
109 t[lc].lazy=maxx(t[lc].lazy,lazy);//debug****
110 t[rc].lazy=maxx(t[rc].lazy,lazy);//debug****
111 }
112
113 void change(int x,int l,int r,int d)
114 {
115 updata(x);
116 if(t[x].l==l && t[x].r==r) {t[x].lazy=d;return;}
117 int lc=t[x].lc,rc=t[x].rc;
118 int mid=(t[x].l+t[x].r)>>1;
119 if(r<=mid) change(lc,l,r,d);
120 else if(l>mid) change(rc,l,r,d);
121 else
122 {
123 change(lc,l,mid,d);
124 change(rc,mid+1,r,d);
125 }
126 updata(lc);
127 updata(rc);
128 t[x].d=maxx(t[lc].d,t[rc].d);
129 }
130
131 int query(int x,int y)
132 {
133 if(t[x].lazy) updata(x);
134 if(t[x].l==t[x].r) return t[x].d;
135 int lc=t[x].lc,rc=t[x].rc;
136 int mid=(t[x].l+t[x].r)>>1;
137 if(y<=mid) return query(lc,y);
138 if(y>mid) return query(rc,y);
139 }
140
141 int dp_AC(int x,int now,int id)
142 {
143 if(x==0) return now;
144 return dp_AC(a[x].fa,maxx(now,query(1,dfn[x])),id);
145 }
146
147 int main()
148 {
149 //freopen("a.in","r",stdin);
150 //freopen("a.out","w",stdout);
151 int T,TT=0;
152 scanf("%d",&T);
153 while(T--)
154 {
155 scanf("%d",&n);
156 num=0;len=0;cnt_dfn=-1;cnt_seg=0;//原本cnt_seg=-1,根节点=0,后来cnt_seg改成0,根节点=1
157 clear(0);
158 memset(first,0,sizeof(first));
159 for(int i=1;i<=n;i++) read_trie(i);
160 build_AC_failtree();
161 make_dfn(0);
162 build_segtree(1,num);
163 //dp
164 int mx=0,x,fx;
165 for(int i=1;i<=n;i++)
166 {
167 x=last[i];
168 fx=dp_AC(x,0,i)+w[i];
169 change(1,dfn[x],next_dfn[x],fx);
170 mx=maxx(mx,fx);
171 }
172 printf("Case #%d: %d\n",++TT,mx);
173 }
174 }