【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 }

 

posted @ 2016-07-18 09:20  拦路雨偏似雪花  阅读(567)  评论(0编辑  收藏  举报