zoukankan      html  css  js  c++  java
  • CF1037H Security

    题目

    不会线段树合并怎么办

    那就硬上主席树啊,树上主席树也可以用来维护(endpos)集合

    首先先来考虑一下(l=1,r=|S|)的情况怎么做

    这是一个非常显然的贪心,我们只需要在(SAM)上匹配这个字符串,一旦无法匹配下去或者已经匹配完成了,我们就强行找一条在这个位置上字典序大一些的一条转移就好了

    现在有了(l,r)的限制,我们只需要保证我们到达的状态在(l,r)里出现过了就好了,于是我们用一个主席树来维护(parent)的子树,就可以维护出(endpos)集合了

    我们每往下匹配一位,就将(l++),因为之前已经有一些长度了,所以(endpos)不能只是大于之前的(l)

    按照上面的方法来匹配就好了

    代码

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #define maxn 200005
    #define M 6000005
    #define re register
    inline int read()
    {
    	char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
    	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();
    	return x;
    }
    struct E{int v,nxt;}e[maxn];
    int lst=1,cnt=1,n,m,__,num,tot,ans,N;
    int l[M],r[M],d[M];
    int len[maxn],endpos[maxn],son[maxn][26],fa[maxn];
    int head[maxn],to[maxn],_to[maxn],sum[maxn],rt[maxn];
    char S[maxn],out[maxn];
    inline void add(int x,int y){e[++num].v=y;e[num].nxt=head[x];head[x]=num;}
    void dfs(int x){to[x]=++__,_to[__]=x;sum[x]=1;for(re int i=head[x];i;i=e[i].nxt) dfs(e[i].v),sum[x]+=sum[e[i].v];}
    inline void ins(int c,int o)
    {
    	int f=lst,p=++cnt; lst=p;
    	len[p]=len[f]+1,endpos[p]=o;
    	while(f&&!son[f][c]) son[f][c]=p,f=fa[f];
    	if(!f) {fa[p]=1;return;}
    	int x=son[f][c];
    	if(len[f]+1==len[x]) {fa[p]=x;return;}
    	int y=++cnt;
    	len[y]=len[f]+1,fa[y]=fa[x],fa[x]=fa[p]=y;
    	for(re int i=0;i<26;i++) son[y][i]=son[x][i];
    	while(f&&son[f][c]==x) son[f][c]=y,f=fa[f];
    }
    int change(int pre,int x,int y,int pos)
    {
    	int root=++tot;
    	d[root]=d[pre]+1;
    	if(x==y) return root;
    	l[root]=l[pre],r[root]=r[pre];
    	int mid=x+y>>1;
    	if(pos<=mid) l[root]=change(l[pre],x,mid,pos);
    		else r[root]=change(r[pre],mid+1,y,pos);
    	return root;
    }
    int query(int p1,int p2,int x,int y,int pos)
    {
    	if(x==y) 
    	{
    		if(pos==x) return d[p2]-d[p1];
    		return 0;
    	}
    	int mid=x+y>>1;
    	if(pos<=mid) return query(l[p1],l[p2],x,mid,pos);
    	return d[l[p2]]-d[l[p1]]+query(r[p1],r[p2],mid+1,y,pos);
    }
    inline int check(int t,int x,int y)
    {
    	int A=to[t],B=to[t]+sum[t]-1;
    	return query(rt[A-1],rt[B],1,N,y)-query(rt[A-1],rt[B],1,N,x-1);
    }
    int work(int now,int x,int y,int L)
    {
    	int b=0;
    	if(L==n+1) 
    	{
    		for(re int i=0;i<26;i++)
    		if(son[now][i]&&check(son[now][i],x,y)) {ans=L,b=1,out[L]=i;break;}
    		return b;
    	}
    	if(son[now][S[L]-'a'])
    	{
    		int t=son[now][S[L]-'a'];
    		if(check(t,x,y)) b=work(t,x+1,y,L+1);
    		if(b) out[L]=S[L]-'a';
    	}
    	if(b) return b;
    	for(re int i=S[L]+1-'a';i<26;i++) 
    	if(son[now][i]&&check(son[now][i],x,y)) {ans=L,b=1,out[L]=i;break;}
    	return b;
    }
    int main()
    {
    	scanf("%s",S+1);n=strlen(S+1);N=n;
    	for(re int i=1;i<=n;i++) ins(S[i]-'a',i);
    	for(re int i=2;i<=cnt;i++) add(fa[i],i); dfs(1);
    	for(re int i=1;i<=cnt;i++)
    	{
    		if(endpos[_to[i]]) rt[i]=change(rt[i-1],1,n,endpos[_to[i]]);
    			else rt[i]=rt[i-1];
    	}
    	m=read();int x,y;
    	while(m--)
    	{
    		x=read(),y=read();
    		scanf("%s",S+1);n=strlen(S+1);
    		if(!work(1,x,y,1)) puts("-1");
    			else {for(re int i=1;i<=ans;i++) putchar(out[i]+'a');putchar(10);}
    	}
    	return 0;
    }
    
  • 相关阅读:
    centos7grub2 引导win10
    必测的支付漏洞(一)——使用fiddler篡改支付金额
    使用Fiddler进行IOS APP的HTTP抓包
    Fiddler实现手机抓包——小白入门
    信息收集工具recon-ng详细使用教程
    Chrome浏览器扩展开发系列之一:初识Google Chrome扩展
    Dear Project Manager, I Hate You
    敏捷中的沟通与故事点
    项目经理与敏捷开发
    C#中使用反射获取结构体实例
  • 原文地址:https://www.cnblogs.com/asuldb/p/10279130.html
Copyright © 2011-2022 走看看