JZOJ5915. 【NOIP2018模拟10.19】明日之星

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/XLno_name/article/details/83187976

题意:

n位舞台少女各自有一个番号,番号是由‘A’、‘C’、‘G’、‘T’、‘U’五种字符组成的字符串,某种未知力量导致不同的舞台少女的番号可能相同。
我们把第i位舞台少女的番号记作s[i],且每位舞台少女还会有一个梦想值a[i]。
舞台少女之间互相建立了友好的关系,如果把关系看作边,那么这是一棵无根树。
giraffe想了一种奇特的点名方式,每次点名它会有一个名单S,S也是由‘A’、‘G’、‘C’、‘T’、‘U’五种字符组成的字符串。
然后它从第u位舞台少女走最短路到第v位舞台少女,对于途中经过的每位舞台少女x(包括u、v),x的分数为 番号s[x]在S中出现的次数 * 梦想值a[x],giraffe想知道分数之和。
当然,舞台少女们随着心情的变化梦想值也是会改变的。
giraffe:“I see.”
谁也不知道giraffe知道的分数和是多少,所以拜托你了。
由于gireffe喜欢未知的舞台,所以本题强制在线。

数据范围:

对于全部数据,保证任意时刻的a[i]满足:
1<=a[i]<=1000,ans<2^31,1<=n,Q<=200000,Sum(|s|),Sum(|S|)<=400000

时限:5S 空间:512MB

Analysis:

首先发现答案显然具有可减性,那么使用括号序肯定最优,次数我们可以使用 A C AC 自动机解决,那么转换为一个二维偏序,但是这时候其他数据结构都会被卡掉(空间,在线),必须要去除其中一个偏序的影响。我们是在整个 A C AC 自动机上搞,所以会有一维偏序,考虑每一次把括号序上的串的 A C AC 自动机构出来。考虑到其是一个区间且 A C AC 自动机形态不变,我们用线段树维护 A C AC 自动机,即对于线段树上每一个节点代表的区间构 A C AC 自动机来搞,那就只剩一维偏序了,空间也不愁。

Code:

# include<cstdio>
# include<cstring>
# include<algorithm>
# include<vector>
using namespace std;
# define ls(x) x << 1
# define rs(x) x << 1 | 1
# define pb push_back
const int N = 8e5 + 5;
const int M = 7e6 + 5;
char s1[N >> 1];
int st[M],to[M],nx[M],a[N >> 1],lx[N >> 1],rt[N << 1],z[M],fail[M],fa[N >> 1][25],c[M << 1],rx[N << 1];
int lc[N],rc[N],ch[M][5],t[M << 1],v[N],s[N >> 1],q[N],in[M],out[M],d[N >> 1],id[N];
int n,m,tot,tp,ans,cnt,num,G,C;
inline int read()
{
	int x = 0; char ch = getchar();
	for (; ch < '0' || ch > '9' ; ch = getchar());
	for (; ch >= '0' && ch <= '9' ; ch = getchar()) x = x * 10 + ch - '0';
	return x;
}
inline void add(int u,int v)
{ to[++num] = v,nx[num] = st[u],st[u] = num; }
inline void ins(int x,int V)
{ for (int i = x ; i <= G ; i += i & (-i)) t[i] += V; }
inline int qry(int x)
{
	int ret = 0;
	for (int i = x ; i ; i -= i & (-i)) ret += t[i];
	return ret;
}
inline void dfs(int x)
{
	lc[x] = ++tot,v[tot] = a[x],id[tot] = x,d[x] = d[fa[x][0]] + 1;
	for (int i = 1 ; i <= 20 ; ++i) fa[x][i] = fa[fa[x][i - 1]][i - 1];
	for (int i = st[x] ; i ; i = nx[i])
	if (to[i] != fa[x][0]) fa[to[i]][0] = x,dfs(to[i]);
	rc[x] = ++tot,v[tot] = -a[x],id[tot] = x;
}
inline void dg(int x)
{
	in[x] = ++G;
	for (int i = st[x] ; i ; i = nx[i]) dg(to[i]);
	out[x] = G;
}
inline int ts(char c)
{
	if (c == 'A') return 0;
	else if (c == 'G') return 1;
	else if (c == 'C') return 2;
	else if (c == 'T') return 3;
	else if (c == 'U') return 4;
}
inline int find(int x,int y)
{
	if (d[x] < d[y]) swap(x,y);
	for (int i = 20 ; ~i ; --i)
	if (d[fa[x][i]] >= d[y]) x = fa[x][i];
	if (x == y) return x;
	for (int i = 20 ; ~i ; --i)
	if (fa[x][i] != fa[y][i]) x = fa[x][i],y = fa[y][i];
	return fa[x][0];
}
inline void build(int x,int l,int r)
{
	rt[x] = ++cnt; rx[x] = C + 1;
	for (int i = l ; i <= r ; ++i)
	{
		int p = rt[x];
		for (int j = lx[id[i]] ; j < lx[id[i] + 1] ; ++j)
		{
			if (!ch[p][s[j]]) ch[p][s[j]] = ++cnt;
			p = ch[p][s[j]];
		} z[p] += v[i];
		c[++C] = p;
	}
	int h = 1,t1 = 0; q[++t1] = rt[x]; for (int i = 0 ; i < 5 ; ++i) ch[0][i] = rt[x];
	while (h <= t1)
	{
		int now = q[h++]; if (now != rt[x]) add(fail[now],now);
		for (int i = 0 ; i < 5 ; ++i)
		if (ch[now][i])
		{
			if (now == rt[x]) fail[ch[now][i]] = rt[x];
			else
			{
				int p = fail[now];
				while (!ch[p][i]) p = fail[p];
				fail[ch[now][i]] = ch[p][i];
			} q[++t1] = ch[now][i];
		}
	} dg(rt[x]);
	if (l == r) return;
	int mid = (l + r) >> 1;
	build(ls(x),l,mid); build(rs(x),mid + 1,r);
}
inline void calc(int x,int l,int r,int l1,int r1)
{
	if (l >= l1 && r <= r1)
	{
		int p = rt[x];
		for (int i = 0 ; i < 5 ; ++i) ch[0][i] = rt[x];
		for (int i = 1 ; i <= strlen(s1 + 1) ; ++i)
		{
			while (!ch[p][ts(s1[i])]) p = fail[p];
			p = ch[p][ts(s1[i])]; ans += qry(in[p]);
		} return;
	}
	int mid = (l + r) >> 1;
	if (l1 <= mid) calc(ls(x),l,mid,l1,r1);
	if (r1 > mid) calc(rs(x),mid + 1,r,l1,r1);
}
inline void gai(int x,int l,int r,int p,int V)
{
	ins(in[c[rx[x] + p - l]],V),ins(out[c[rx[x] + p - l]] + 1,-V);
	if (l == r) return;
	int mid = (l + r) >> 1;
	if (p <= mid) gai(ls(x),l,mid,p,V);
	else gai(rs(x),mid + 1,r,p,V);
}
int main()
{
	freopen("light.in","r",stdin);
	freopen("light.out","w",stdout);
	n = read(),tp = read(); lx[1] = 1;
	for (int i = 1 ; i <= n ; ++i)
	{
		scanf("%s",s1 + 1); lx[i + 1] = lx[i] + strlen(s1 + 1);
		for (int j = lx[i] ; j < lx[i + 1] ; ++j) s[j] = ts(s1[j - lx[i] + 1]);
	}
	for (int i = 1 ; i <= n ; ++i) a[i] = read();
	for (int i = 1 ; i < n ; ++i)
	{
		int u = read(),v = read();
		add(u,v),add(v,u);
	}
	num = 0,dfs(1);
	memset(st,0,sizeof(st));
	build(1,1,tot);
	for (int i = 1 ; i <= cnt ; ++i) if (z[i] != 0) ins(in[i],z[i]),ins(out[i] + 1,-z[i]);
	m = read();
	while (m--)
	{
		int opt = read(),x = ans * tp ^ read(),y = ans * tp ^ read();
		if (opt == 1)
		{
			scanf("%s",s1 + 1); int lca = find(x,y); ans = 0;
			calc(1,1,tot,lc[lca],lc[x]);
			if (lc[lca] + 1 <= lc[y]) calc(1,1,tot,lc[lca] + 1,lc[y]);
			printf("%d\n",ans);
		}else
		{
			int del = y - a[x]; a[x] = y;
			gai(1,1,tot,lc[x],del); gai(1,1,tot,rc[x],-del);
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/XLno_name/article/details/83187976