1. 程式人生 > 其它 >CF163E e-Government(AC自動機+樹剖)

CF163E e-Government(AC自動機+樹剖)

給出n個字串。每個字串最初的權值都是0。

請你支援以下兩種操作:

1)把第i個字串的權值改成x。

2)給出一個文字串q,詢問所有字串中,是q的子串的最大權值。

做法:

首先對所有字串建立AC自動機。

假設所有字串互不相同。

輸入一個文字串,對於文字串的第i個節點,它到根節點的路徑的權值最大值就是答案

修改+詢問的過程樹鏈剖分維護就行。

對於兩個完全一樣但是編號不同的字串,把相同字串的編號存到一個vector裡。

先標記每個編號屬於哪個vector,然後對該vector用樹狀陣列的形式維護最大值。

修改的時候用vector的最大值去更新節點的權值。

詢問的時候樹鏈剖分處理即可。

#include<bits/stdc++.h>
using namespace std;
const int maxn=3e5+100;
int lowbit (int x) {
	return x&-x;
}
int n,m;
vector<int> g[maxn];
int son[maxn],id[maxn],fa[maxn],cnt,dep[maxn],sz[maxn],top[maxn],w[maxn],wt[maxn];
int c[maxn<<2];
int tot,tr[maxn][26],fail[maxn];
string s;

void up (int i,int l,int r,int p,int v) {
	if (l==p&&r==p) {
		c[i]=v;
		return;
	}
	int mid=(l+r)>>1;
	if (p<=mid) up(i<<1,l,mid,p,v);
	if (p>mid) up(i<<1|1,mid+1,r,p,v);
	c[i]=max(c[i<<1],c[i<<1|1]);
}
int query (int i,int l,int r,int L,int R) {
	if (l>=L&&r<=R) return c[i];
	int mid=(l+r)>>1;
	int ans=0;
	if (L<=mid) ans=max(ans,query(i<<1,l,mid,L,R));
	if (R>mid) ans=max(ans,query(i<<1|1,mid+1,r,L,R));
	return ans;
}
int qRange (int x,int y) {
	int ans=0;
	while (top[x]!=top[y]) {
		if (dep[top[x]]<dep[top[y]]) swap(x,y);
		ans=max(ans,query(1,1,cnt,id[top[x]],id[x]));
		x=fa[top[x]];
	}
	if (dep[x]>dep[y]) swap(x,y);
	ans=max(ans,query(1,1,cnt,id[x],id[y]));
	return ans;
}
void dfs1 (int x,int f,int deep) {
	dep[x]=deep;
	fa[x]=f;
	sz[x]=1;
	w[x]+=w[f];
	int maxson=-1;
	for (int y:g[x]) {
		if (y==f) continue;
		dfs1(y,x,deep+1);
		sz[x]+=sz[y];
		if (sz[y]>maxson) son[x]=y,maxson=sz[y];
	}
}
void dfs2 (int x,int topf) {
	id[x]=++cnt;
	top[x]=topf;
	if (!son[x]) return;
	dfs2(son[x],topf);
	for (int y:g[x]) {
		if (y==fa[x]||y==son[x]) continue;
		dfs2(y,y);
	}
} 

vector<int> G[maxn];
vector<int> GC[maxn];
void up1 (int i,int l,int r,int p,int v,int x) {
	if (l==p&&r==p) {
		GC[x][i]=v;
		return;
	}
	int mid=(l+r)>>1;
	if (p<=mid) up1(i<<1,l,mid,p,v,x);
	if (p>mid) up1(i<<1|1,mid+1,r,p,v,x);
	GC[x][i]=max(GC[x][i<<1],GC[x][i<<1|1]);
}
int b[maxn],bb[maxn];
int insert (string s) {
	int u=0;
	for (char i:s) {
		if (!tr[u][i-'a']) tr[u][i-'a']=++tot;
		u=tr[u][i-'a'];
	}
	w[u]++;
	return u;
}
void build () {
	queue<int> q;
	for (int i=0;i<26;i++) {
		if (tr[0][i]) {
			q.push(tr[0][i]);
		}
	}
	while (q.size()) {
		int u=q.front();
		q.pop();
		for (int i=0;i<26;i++) {
			if (tr[u][i]) {
				fail[tr[u][i]]=tr[fail[u]][i];
				q.push(tr[u][i]);
			}
			else {
				tr[u][i]=tr[fail[u]][i];
			}
		}
	}
}
int main () {
	ios::sync_with_stdio(false);
	cin>>n>>m;
	for (int i=1;i<=n;i++) {
		cin>>s;
		int x=insert(s);
		bb[i]=x;
		b[i]=G[x].size();
		G[x].push_back(i);
	}
	for (int i=1;i<maxn;i++) {
		while (GC[i].size()<=G[i].size()*5) GC[i].push_back(0);
	}
	build();
	for (int i=1;i<=tot;i++) {
		g[fail[i]].push_back(i);
	}
	dfs1(0,0,1);
	dfs2(0,0);
	while (m--) {
		string op;
		cin>>op;
		if (op=="2") {
			string t;
			cin>>t;
			int u=0;
			int ans=0;
			int tt=0;
			for (char i:t) {
				u=tr[u][i-'a'];
				tt+=w[u];
				ans=max(ans,qRange(0,u));
			}
			if (!tt) ans=-1;
			printf("%d\n",ans);
		}
		else {
			int x,xx;
			cin>>x>>xx;
			up1(1,0,G[bb[x]].size()-1,b[x],xx,bb[x]);
			up(1,1,cnt,id[bb[x]],GC[bb[x]][1]);
		}
	}
}