• [CF666E] Forensic Examination


    题目链接

    codeforces.

    洛谷.

    Solution

    典型的码农题...

    思路很简单,对字符串数组建立广义(SAM),然后把(s)扔进去跑,预处理匹配长度和匹配点,然后每次倍增跳,答案就直接上线段树合并就好了。

    注意我也不知道为什么但是线段树合并好像不能基数排序后搞,否则会出事,如果你是wrong answer on test 6可能就是这个问题,具体可以看我代码注释部分。

    输出格式注意下,无解输出(l,0)

    #include<bits/stdc++.h>
    using namespace std;
     
    void read(int &x) {
        x=0;int f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
     
    void print(int x) {
        if(x<0) putchar('-'),x=-x;
        if(!x) return ;print(x/10),putchar(x%10+48);
    }
    void write(int x) {if(!x) putchar('0');else print(x);putchar('
    ');}
    
    #define lf double
    #define ll long long 
    #define mid ((l+r)>>1)
    
    struct pii {
    	int fr,sc;
    	bool operator < (const pii b) const {return fr==b.fr?sc>b.sc:fr<b.fr;}
    };
    
    const int maxn = 1e6+10;
    const int inf = 1e9;
    const lf eps = 1e-8;
    
    int rt[maxn];
    
    namespace sgt {
    	int sg,ls[maxn*20],rs[maxn*20];
    	pii t[maxn*20];   //线段树记录最大值和最大值来自哪里,注意要满足编号尽可能小
    	
    	void insert(int &p,int l,int r,int x) {
    		if(!p) p=++sg;
    		if(l==r) return t[p]=(pii){1,l},void();
    		if(x<=mid) insert(ls[p],l,mid,x);
    		else insert(rs[p],mid+1,r,x);
    		t[p]=max(t[ls[p]],t[rs[p]]);
    	}
    	
    	pii query(int p,int l,int r,int x,int y) {
    		if(!p) return (pii){0,0};
    		if(x<=l&&r<=y) return t[p];
    		pii res=(pii){0,0};
    		if(x<=mid) res=max(res,query(ls[p],l,mid,x,y));
    		if(y>mid) res=max(res,query(rs[p],mid+1,r,x,y));
    		return res;
    	}
    	
    	int merge(int x,int y,int l,int r) {
    		if(!x||!y) return x+y;
    		int now=++sg;
    		if(l==r) return t[now]=t[x],t[now].fr+=t[y].fr,now;
    		ls[now]=merge(ls[x],ls[y],l,mid);
    		rs[now]=merge(rs[x],rs[y],mid+1,r);
    		t[now]=max(t[ls[now]],t[rs[now]]);
    		return now;
    	}
    }
    
    int n;
    char s[maxn],c[maxn];
    
    namespace sam {
    	int tr[maxn][26],lstp,cnt=1,sum[maxn],r[maxn],ml[maxn],par[maxn],fa[maxn][20],pos[maxn],mx[maxn];
    	void append(int x,int bel) {
    		int p=lstp,np=++cnt;ml[np]=ml[p]+1;lstp=np;
    		sgt :: insert(rt[np],1,n,bel);
    		for(;p&&tr[p][x]==0;p=par[p]) tr[p][x]=np;
    		if(!p) return par[np]=1,void();
    		int q=tr[p][x];
    		if(ml[p]+1<ml[q]) {
    			int nq=++cnt;ml[nq]=ml[p]+1;
    			memcpy(tr[nq],tr[q],sizeof tr[nq]);
    			par[nq]=par[q],par[q]=par[np]=nq;
    			for(;p&&tr[p][x]==q;p=par[p]) tr[p][x]=nq;
    		} else par[np]=q;
    	}
    
    	struct Tree {	
    		int head[maxn],tot;
    		struct edge{int to,nxt;}e[maxn<<1];
    		void add(int u,int v) {e[++tot]=(edge){v,head[u]},head[u]=tot;}
    
    		void dfs(int x) {
    			fa[x][0]=par[x];
    			for(int i=1;i<=16;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
    			for(int i=head[x];i;i=e[i].nxt)
    				dfs(e[i].to),rt[x]=sgt::merge(rt[x],rt[e[i].to],1,n);  //在这里线段树合并
    		}
    	}T;
    
    	void prepare() {
    		for(int i=2;i<=cnt;i++) T.add(par[i],i);   //这里,好像必须要把parent树建出来然后
    		T.dfs(1);                                  //线段树合并,否则算不对
    		
    		int len=strlen(s+1),now=1,l=0;
    		for(int i=1,v;i<=len;i++) {
    			v=s[i]-'a';
    			if(tr[now][v]) now=tr[now][v],l++;
    			else {
    				while((!tr[now][v])&&now) now=par[now];
    				if(!now) now=1,l=0;
    				else l=ml[now]+1,now=tr[now][v];
    			}
    			pos[i]=now,mx[i]=l;
    		}
    	}
    
    	void solve() {
    		int l,R,pl,pr;read(l),read(R),read(pl),read(pr);
    		int now=pos[pr];
    		if(mx[pr]<pr-pl+1) return printf("%d 0
    ",l),void();
    		for(int i=16;~i;i--)
    			if(ml[fa[now][i]]>=pr-pl+1) now=fa[now][i];
    		pii res=sgt::query(rt[now],1,n,l,R);
    		if(res.fr==0) res.sc=l;
    		printf("%d %d
    ",res.sc,res.fr);  
    	}
    }
    
    int main() {
    	scanf("%s",s+1);read(n);
    	for(int i=1;i<=n;i++) {geshi
    		scanf("%s",c+1);int len=strlen(c+1);sam::lstp=1;
    		for(int j=1;j<=len;j++) sam::append(c[j]-'a',i);
    	}
    	sam :: prepare();
    	int q;read(q);
    	for(int i=1;i<=q;i++) sam :: solve();
    	return 0;
    }
    
  • 相关阅读:
    Maven介绍
    自考:计算机网络原理 2018版 李全龙 课后习题答案
    jmeter分布式部署遇到的坑
    mysql循环 insert插入多条数据
    认识Nacos.
    mysql中where子句中使用别名查询出现问题
    python之bytes和string相互转换
    什么叫线圈?什么寄存器?什么叫保持寄存器?
    Modbus-RTU详解(转载)
    python进制之间的转换函数
  • 原文地址:https://www.cnblogs.com/hbyer/p/10592875.html
Copyright © 2020-2023  润新知