【NOIp训练】—子串查找VII(AC自动机+树链剖分+线段树)
题意:
给定个点的树,树上每个节点存有一个字符串和权值
有次询问
每次给定一个字符串和树上一条路径
询问每个节点的之和
支持修改点的权值
结果数据水的我跑过去了(跑了)
一个很简单的想法是对原树建一颗线段树
对于线段树上每一个节点把区间内所有点拿出来建一个自动机
每次就只用在个节点内暴力匹配就可以了
考虑修改
对自动机上一个终点修改权值会影响树上所有子孙
所以还需要写一个线段树维护序
这样就做到询问,修改了
结果时间空间常数都十分巨大
空间明明是结果是需要开个
被踩爆了
#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);
}
}
}