• 打击目标


    Portal --> broken

    Description

    ​  给你一棵有根树((1)为根节点),每个节点有一个对应的字符串,现在给出若干询问,每次询问(x)(y)路径上的点的字符串中,是给定串(S)的子串的字符串的最长长度

    ​  部分数据强制在线

    ​​  数据范围:(n<=10^5,sum|w|<=10^5,1<=|m[i]|<=10),其中(w)是每次询问中的(S)的长度,(m[i])表示的是第(i)个节点对应的字符串

    ​  

    Solution

    ​  场上想了一下应该是。。什么ac自动机和线段树套在一起的树剖==

    ​  然后特别愚蠢地把ac自动机套在了线段树里面我也真是有勇气qwq然后这个洋溢着梦想气息的做法获得了(50)分的好成绩==

    ​​  一种做法是一开始先对所有的(m[i])建出ac自动机,建出fail树,然后。。再套一个主席树什么的,查询的时候边在fail树上面跑边在主席树里面查路径对应区间的最大值(大概是这样。。具体细节没有细想qwq)

    ​  

    ​  然而实际上。。我们为什么一定要用ac自动机呢0.0

    ​  注意到(m[i])很小,然后数据又对(sum|w|)有限制,所以。。我们可以直接暴力枚举每次询问中(S)的长度(<=10)的子串,然后剩下的事情就是查路径上面是否有这个子串就好了==

    ​  具体实现的话我们可以先把所有的(m[i])哈希一下,然后离散化一下,然后查的时候先lower_bound一下什么的就好了

    ​  

    ​​  mark:提醒自己不能写数据结构写傻了啊==数据范围还是很重要的。。对这种小的不正常的范围一定要足够敏感才行

    ​  

    ​  代码大概长这个样子

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define ull unsigned long long
    using namespace std;
    const int N=1e5+10,TOP=17,Hs=19260817;
    struct xxx{
    	int y,nxt;
    }a[N];
    char s[N][15],S[N];
    ull val[N],lis[N],pw[N],V[N];
    int id[N];
    int h[N],f[N][TOP+1],dep[N];
    int n,m,tot,lastans,O,dfn_t;
    namespace Seg{/*{{{*/
    	const int N=::N*20;
    	int ch[N][2],sum[N],rt[::N];
    	int n,tot;
    	void init(int _n){n=_n; tot=0;}
    	int newnode(int pre){
    		ch[++tot][0]=ch[pre][0]; ch[tot][1]=ch[pre][1]; sum[tot]=sum[pre];
    		return tot;
    	}
    	void _insert(int pre,int &x,int d,int lx,int rx){
    		x=newnode(pre);
    		++sum[x];
    		if (lx==rx) return;
    		int mid=lx+rx>>1;
    		if (d<=mid) _insert(ch[pre][0],ch[x][0],d,lx,mid);
    		else _insert(ch[pre][1],ch[x][1],d,mid+1,rx);
    	}
    	void insert(int pre,int x,int d){_insert(rt[pre],rt[x],d,1,n);}
    	int _query(int x,int y,int lca,int d,int lx,int rx){
    		if (lx==rx) return sum[x]+sum[y]-sum[lca]*2;
    		int mid=lx+rx>>1;
    		if (d<=mid) return _query(ch[x][0],ch[y][0],ch[lca][0],d,lx,mid);
    		else return _query(ch[x][1],ch[y][1],ch[lca][1],d,mid+1,rx);
    	}
    	int query(int x,int y,int lca,int d){return _query(rt[x],rt[y],rt[lca],d,1,n);}
    }/*}}}*/
    void add(int x,int y){a[++tot].y=y; a[tot].nxt=h[x]; h[x]=tot;}
    void dfs(int fa,int x,int d){
    	int u;
    	dep[x]=d; f[x][0]=fa; 
    	Seg::insert(fa,x,id[x]);
    	for (int i=1;i<=TOP;++i) f[x][i]=f[f[x][i-1]][i-1];
    	for (int i=h[x];i!=-1;i=a[i].nxt){
    		u=a[i].y;
    		dfs(x,u,d+1);
    	}
    }
    int get_lca(int x,int y){
    	if (dep[x]<dep[y]) swap(x,y);
    	for (int i=TOP;i>=0;--i)
    		if (dep[f[x][i]]>=dep[y]) x=f[x][i];
    	if (x==y) return x;
    	for (int i=TOP;i>=0;--i)
    		if (f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    	return f[x][0];
    }
    void prework(){
    	int len;
    	lis[0]=0;
    	for (int i=1;i<=n;++i){
    		len=strlen(s[i]);
    		val[i]=0;
    		for (int j=0;j<len;++j) val[i]=val[i]*Hs+s[i][j]-'a'+1;
    		lis[++lis[0]]=val[i];
    	}
    	sort(lis+1,lis+1+lis[0]);
    	lis[0]=unique(lis+1,lis+1+lis[0])-lis-1;
    	for (int i=1;i<=n;++i)
    		id[i]=lower_bound(lis+1,lis+1+lis[0],val[i])-lis;
    	Seg::init(lis[0]);
    	pw[0]=1;
    	for (int i=1;i<=1e5;++i) pw[i]=pw[i-1]*Hs;
    }
    ull get_val(int l,int r){
    	return V[r]-V[l-1]*pw[r-l+1];
    }
    void solve(int x,int y){
    	int lca=get_lca(x,y),lenS=strlen(S);
    	int pos;
    	ull tmp;
    	lastans=0;
    	V[0]=S[0]-'a'+1;
    	for (int i=1;i<lenS;++i) V[i]=V[i-1]*Hs+S[i]-'a'+1;
    	for (int len=10;len>=0;--len){
    		for (int i=0;i+len-1<lenS;++i){
    			tmp=get_val(i,i+len-1);
    			pos=lower_bound(lis+1,lis+1+lis[0],tmp)-lis;
    			if (lis[pos]!=tmp) continue;
    			if (Seg::query(x,y,lca,pos)+(id[lca]==pos)){lastans=len;return;}
    		}
    	}
    }
    
    int main(){
    #ifndef ONLINE_JUDGE
    	freopen("a.in","r",stdin);
    #endif
    	int x,y;
    	scanf("%d%d",&n,&O);
    	for (int i=1;i<=n;++i) scanf("%s",s[i]);
    	prework();
    	memset(h,-1,sizeof(h));
    	tot=0; lastans=0;
    	for (int i=2;i<=n;++i){
    		scanf("%d",&x);
    		add(x,i);
    	}
    	dfs(0,1,1);
    	scanf("%d",&m);
    	for (int i=1;i<=m;++i){
    		scanf("%d%d%s",&x,&y,S);
    		x^=lastans*O;
    		y^=lastans*O;
    		solve(x,y);
    		printf("%d
    ",lastans);
    	}
    }
    
  • 相关阅读:
    分布式缓存技术之Redis_03分布式redis
    Spring 二、400行代码手写初体验Spring V1.0版本
    Spring 一、各级架构与依赖关系
    Java正则表达式基础学习
    JAVA开发:SpringBoot多数据源配置
    Spring 单例模式实现源码分析
    Spring 使用的设计模式用哪些
    Spring之@Autowired和@Resource
    Spring的优缺点
    MySQL支持的事物隔离级别以及悲观锁和乐观锁原理和应用场景
  • 原文地址:https://www.cnblogs.com/yoyoball/p/9751290.html
Copyright © 2020-2023  润新知