【NOIp训练】—子串查找VII(AC自动机+树链剖分+线段树)

传送门

题意:

给定nn个点的树,树上每个节点存有一个字符串ss和权值vv
mm次询问
每次给定一个字符串SS和树上一条路径
询问每个节点的sS×vs在S中出现次数\times v之和
支持修改点的权值

n,m2e5,S,s4e5n,m\le2e5,\sum|S|,|s|\le 4e5


结果数据水的我O(nlog3n)O(nlog^3n)跑过去了(跑了11s11s

一个很简单的想法是对原树建一颗线段树
对于线段树上每一个节点把区间内所有点拿出来建一个AcAc自动机

每次就只用在O(log2n)O(log^2n)个节点内暴力匹配就可以了

考虑修改
AcAc自动机上一个终点修改权值会影响failfail树上所有子孙
所以还需要写一个线段树维护dfsdfs

这样就做到询问O(log3n)O(log^3n),修改O(log2n)O(log^2n)
结果时间空间常数都十分巨大
空间明明是O(nlogn)O(nlogn)结果是需要开1.51.5GG

ldxldx踩爆了

#include<bits/stdc++.h>
using namespace std;
const int RLEN=1<<20|1;
inline char gc(){
	static char ibuf[RLEN],*ib,*ob;
	(ob==ib)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ob==ib)?EOF:*ib++;
}
#define gc getchar
inline int read(){
	char ch=gc();
	int res=0,f=1;
	while(!isdigit(ch))f^=ch=='-',ch=gc();
	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
	return f?res:-res;
}
#define ll long long
inline ll readl(){
	char ch=gc();
	ll res=0,f=1;
	while(!isdigit(ch))f^=ch=='-',ch=gc();
	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
	return f?res:-res;
}
#define re register
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define pob pop_back
#define cs const
#define poly vector<int>
#define db double
#define bg begin
inline void chemx(int &a,int b){a<b?a=b:0;}
inline void chemn(int &a,int b){a>b?a=b:0;}
cs int N=400005;
#define lc (u<<1)
#define rc ((u<<1)|1)
#define mid ((l+r)>>1)
char x;
int val[N*20],tot;
struct node{
	int nxt[5],fail;
	node(){memset(nxt,0,sizeof(nxt)),fail=0;}
};
node p[N*20];
vector<int>e[N*20];
int in[N*20],out[N*20];
struct Ac{
	vector<ll>tag;
	int dfn,rt;
	vector<int> stk;
	vector<int> idx;
	map<int,ll>ed,a;
	inline void initac(){
		rt=newnode();
	}
	void buildt(int u,int l,int r){
		if(l==r){tag[u]=val[idx[l]];return;}
		buildt(lc,l,mid),buildt(rc,mid+1,r);
	}
	inline void init(){tag.resize(dfn<<2,0);buildt(1,1,dfn);}
	void update(int u,int l,int r,int st,int des,ll k){
		if(st<=l&&r<=des){tag[u]+=k;return;}
		if(st<=mid)update(lc,l,mid,st,des,k);
		if(mid<des)update(rc,mid+1,r,st,des,k);
	}
	ll query(int u,int l,int r,int p){
		if(l==r)return tag[u];
		if(p<=mid)return tag[u]+query(lc,l,mid,p);
		else return tag[u]+query(rc,mid+1,r,p);
	}
	inline int newnode(){
		tot++,stk.pb(tot);
		return tot;
	}
	inline void insert(vector<int> &s,int id,ll v){
		int u=rt;
		for(int i=0,len=s.size();i<len;i++){
			int c=s[i];
			if(!p[u].nxt[c])p[u].nxt[c]=newnode();
			u=p[u].nxt[c];
		}
		ed[id]=u,a[id]=v,val[u]+=v;
	}
	inline void buildfail(){
		queue<int> q;
		for(int i=0;i<5;i++){
			if(p[rt].nxt[i])q.push(p[rt].nxt[i]),p[p[rt].nxt[i]].fail=rt;
			else p[rt].nxt[i]=rt;
		} 
		while(!q.empty()){
			int u=q.front();q.pop();
			for(int i=0;i<5;i++){
				int v=p[u].nxt[i];
				if(!v)p[u].nxt[i]=p[p[u].fail].nxt[i];
				else p[v].fail=p[p[u].fail].nxt[i],q.push(v);
			}
			val[u]+=val[p[u].fail];
		}
	}
	void dfs1(int u){
		in[u]=++dfn;
		idx[dfn]=u;
		for(int &v:e[u])
		dfs1(v);
		out[u]=dfn;
	}
	inline void build(){
		buildfail();
		idx.resize(stk.size()+1);
		for(int i=1;i<stk.size();i++)
		e[p[stk[i]].fail].pb(stk[i]);
		dfs1(rt);
		init();
	}
	inline void updatenode(int id,ll v){
		ll pre=a[id];int u=ed[id];
		update(1,1,dfn,in[u],out[u],v-pre);
		a[id]=v;
	}
	inline ll querynode(vector<int> &s){
		int u=rt;ll res=0;
		for(int i=0,len=s.size();i<len;i++){
			int c=s[i];
			u=p[u].nxt[c];
			res+=query(1,1,dfn,in[u]);
		}
		return res;
	}
};
Ac tr[N<<2];
int n,tp;
ll last;
inline int check(char x){
	switch(x){
		case 'A':{return 0;break;}
		case 'G':{return 1;break;}
		case 'C':{return 2;break;}
		case 'T':{return 3;break;}
		case 'U':{return 4;break;}
	}
}
vector<int> s[N];
char str[N];
ll a[N];
vector<int> E[N];
int fa[N],pos[N],idx[N],siz[N],son[N],top[N],dep[N],dfn;
namespace Tr{
	inline void addedge(int u,int v){
		E[u].pb(v),E[v].pb(u);
	}
	void build(int u,int l,int r){
		tr[u].initac();
		for(int i=l;i<=r;i++)tr[u].insert(s[idx[i]],idx[i],a[idx[i]]);
		tr[u].build();
		if(l==r){return;}
		build(lc,l,mid),build(rc,mid+1,r);
	}
	ll query(int u,int l,int r,int st,int des,vector<int> &k){
		if(st<=l&&r<=des)return tr[u].querynode(k);
		ll res=0;
		if(st<=mid)res+=query(lc,l,mid,st,des,k);
		if(mid<des)res+=query(rc,mid+1,r,st,des,k);
		return res;
	}
	void update(int u,int l,int r,int p,int id,ll k){
		tr[u].updatenode(id,k);
		if(l==r)return;
		if(p<=mid)update(lc,l,mid,p,id,k);
		else update(rc,mid+1,r,p,id,k);
	}
	inline ll pathquery(int u,int v,vector<int> &k){
		ll res=0;
		while(top[u]!=top[v]){
			if(dep[top[u]]<dep[top[v]])swap(u,v);
			res+=query(1,1,n,pos[top[u]],pos[u],k);
			u=fa[top[u]];
		}
		if(dep[u]<dep[v])swap(v,u);
		res+=query(1,1,n,pos[v],pos[u],k);
		return res;
	}
	void dfs1(int u){
		siz[u]=1;
		for(int &v:E[u]){
			if(v==fa[u])continue;
			dep[v]=dep[u]+1,fa[v]=u;
			dfs1(v),siz[u]+=siz[v];
			if(siz[v]>siz[son[u]])son[u]=v;
		}
	}
	void dfs2(int u,int tp){
		top[u]=tp,pos[u]=++dfn,idx[dfn]=u;
		if(son[u])dfs2(son[u],tp);
		for(int &v:E[u]){
			if(v==fa[u]||v==son[u])continue;
			dfs2(v,v);
		}
	}
}
char y;
signed main(){
	n=read(),tp=read();
	for(int i=1;i<=n;i++){
		scanf("%s",str+1);
		for(int j=1,len=strlen(str+1);j<=len;j++)
		s[i].pb(check(str[j]));
	}
	for(int i=1;i<=n;i++)a[i]=readl();
	for(int i=1;i<n;i++){
		int u=read(),v=read();
		Tr::addedge(u,v);
	}
	Tr::dfs1(1);
	Tr::dfs2(1,1);
	Tr::build(1,1,n);
	int q=read();
	while(q--){
		int op=read();
		if(op==1){
			int u=readl()^(last*tp),v=readl()^(last*tp);
			scanf("%s",str+1);vector<int> qq;
			for(int i=1,len=strlen(str+1);i<=len;i++)
			qq.pb(check(str[i]));
			cout<<(last=Tr::pathquery(u,v,qq))<<'\n';
		}
		else{
			int x=readl()^(last*tp);ll c=readl()^(last*tp);
			Tr::update(1,1,n,pos[x],x,c);
		}
	}
}
posted @ 2019-08-24 14:55  Stargazer_cykoi  阅读(128)  评论(0编辑  收藏  举报