• [洛谷P4482] BJWC2018 Border的四种求法


    题目链接

    洛谷

    解析

    考虑转化一下问题,即对每个询问求最大的 (iin[l,r)) 满足 (i-l+1le ext{LCS}(i,r))

    我们先建一棵后缀树,并用线段树合并维护每个节点的 ( ext{endpos}) 集合。后缀树有这样一个性质:两个字符串的 ( ext{LCS}) 就是这两个字符串对应的点在后缀树上的 ( ext{LCA})(len) 值。因此,对于每一个询问,先确定 (r) 代表的前缀所在的点,然后暴力向上跳父亲。每经过一个点就在它的线段树中查询最大的满足要求的 (i) ,这就是一个线段树区间最大值问题。

    现在用树链剖分优化一下上面的过程。每个点到根节点的路径可以拆成若干条重链的前缀,所以我们把每一个询问都拆到这若干个前缀的最后一个点上。对于一条重链,然后从上往下依次枚举重链上的点。考虑如何统计答案:当前点 (x) 是其所有轻子树中的点与询问点的 ( ext{LCA}) ,也就是说轻子树中的点与前缀 (S_r)( ext{LCP}) 是相同的。因此,我们设 (val_i=i-len_x),我们要求的就是满足 (val_i<l)(iin [l,r]) 的最大的 (i) 。因此,我们每到一个节点,就把这个节点的所有轻子树的 (val) 加入一个线段树中,那么挂在这个点上的询问的答案由两部分组成:在上面所说的线段树中二分得到的 (i) 和这个 (i)( ext{endpos}) 集合中最大的满足要求的 (i)

    具体实现时,可以先处理与当前重链相关的所有重链,然后在按照上面的过程。每个点加入线段树的次数不会超过(log) 次,因此复杂度是 (O(nlog ^2n))

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #define N 400002
    using namespace std;
    struct query{
    	int l,r,id;
    	query(){}
    	query(int _l,int _r,int _id){
    		l=_l;r=_r;id=_id;
    	}
    }a[N];
    char s[N];
    int head[N],ver[N],nxt[N],l;
    int n,m,i,size[N],son[N],fa[N],dep[N],top[N],ans[N];
    vector<query> v[N];
    struct SAM{
    	struct node{
    		int len,link,son[26];
    	}t[N*2];
    	int pos[N],id[N*2],cnt,last;
    	void extend(char s,int i){
    		int cur=++cnt,now=last,x=(int)(s-'a');
    		t[cur].len=t[now].len+1;
    		id[cur]=i;pos[i]=cur;
    		while(now&&!t[now].son[x]){
    			t[now].son[x]=cur;
    			now=t[now].link;
    		}
    		if(now==0) t[cur].link=1;
    		else{
    			int p=now,q=t[p].son[x];
    			if(t[q].len==t[p].len+1) t[cur].link=q;
    			else{
    				int p=now,q=t[p].son[x];
    				if(t[q].len==t[p].len+1) t[cur].link=q;
    				else{
    					int tmp=++cnt;
    					t[tmp]=t[q];
    					t[tmp].len=t[p].len+1;
    					t[q].link=t[cur].link=tmp;
    					while(p&&t[p].son[x]==q){
    						t[p].son[x]=tmp;
    						p=t[p].link;
    					}
    				}
    			}
    		}
    		last=cur;
    	}
    }P;
    struct SegmentTree1{
    	struct node{
    		int l,r,dat;
    	}t[N*20];
    	int cnt,root[N];
    	void change(int &p,int l,int r,int x,int v){
    		if(!p) p=++cnt;
    		if(l==r){
    			t[p].dat=v;
    			return;
    		}
    		int mid=(l+r)/2;
    		if(x<=mid) change(t[p].l,l,mid,x,v);
    		else change(t[p].r,mid+1,r,x,v);
    		t[p].dat=max(t[t[p].l].dat,t[t[p].r].dat);
    	}
    	int ask(int p,int l,int r,int ql,int qr){
    		if(!p) return 0;
    		if(ql<=l&&r<=qr) return t[p].dat;
    		int mid=(l+r)/2,ans=0;
    		if(ql<=mid) ans=max(ans,ask(t[p].l,l,mid,ql,qr));
    		if(qr>mid) ans=max(ans,ask(t[p].r,mid+1,r,ql,qr));
    		return ans;
    	}
    	int merge(int x,int y){
    		if(x==0) return y;
    		if(y==0) return x;
    		t[x].l=merge(t[x].l,t[y].l);
    		t[x].r=merge(t[x].r,t[y].r);
    		t[x].dat=max(t[t[x].l].dat,t[t[x].r].dat);
    		return x;
    	}
    }A;
    struct SegmentTree2{
    	struct node{
    		int l,r,dat;
    	}t[N*4];
    	int cnt,root;
    	void clear(){cnt=root=0;}
    	int newnode(){
    		cnt++;
    		t[cnt].l=t[cnt].r=0;t[cnt].dat=1<<30;
    		return cnt;
    	}
    	void change(int &p,int l,int r,int x,int v){
    		if(!p) p=newnode();
    		if(l==r){
    			t[p].dat=v;
    			return;
    		}
    		int mid=(l+r)/2;
    		if(x<=mid) change(t[p].l,l,mid,x,v);
    		else change(t[p].r,mid+1,r,x,v);
    		t[p].dat=min(t[t[p].l].dat,t[t[p].r].dat);
    	}
    	int ask(int p,int l,int r,int ql,int qr,int x){
    		if(p==0||t[p].dat>=x) return 0;
    		if(l==r) return (t[p].dat<x)?l:0;
    		int mid=(l+r)/2;
    		if(ql<=l&&r<=qr){
    			if(t[t[p].r].dat<x) return ask(t[p].r,mid+1,r,ql,qr,x);
    			else return ask(t[p].l,l,mid,ql,qr,x);
    		}
    		else{
    			int ans=0;
    			if(qr>mid) ans=ask(t[p].r,mid+1,r,ql,qr,x);
    			if(ans==0&&ql<=mid) ans=ask(t[p].l,l,mid,ql,qr,x);
    			return ans;
    		}
    	}
    }B;
    void insert(int x,int y)
    {
    	l++;
    	ver[l]=y;
    	nxt[l]=head[x];
    	head[x]=l;
    }
    void dfs1(int x,int pre)
    {
    	size[x]=1;fa[x]=pre;
    	dep[x]=dep[pre]+1;
    	for(int i=head[x];i;i=nxt[i]){
    		int y=ver[i];
    		dfs1(y,x);
    		size[x]+=size[y];
    		if(size[y]>size[son[x]]) son[x]=y;
    	}
    }
    void dfs2(int x,int t)
    {
    	top[x]=t;
    	if(son[x]) dfs2(son[x],t);
    	for(int i=head[x];i;i=nxt[i]){
    		int y=ver[i];
    		if(y!=son[x]) dfs2(y,y);
    	}
    }
    void dfs(int x)
    {
    	for(int i=head[x];i;i=nxt[i]){
    		int y=ver[i];
    		dfs(y);
    		A.root[x]=A.merge(A.root[x],A.root[y]);
    	}
    	A.change(A.root[x],1,n,P.id[x],P.id[x]);
    	for(int i=0;i<v[x].size();i++){
    		int r=min(v[x][i].r,P.t[x].len+v[x][i].l);
    		if(v[x][i].l<=r-1) ans[v[x][i].id]=max(ans[v[x][i].id],A.ask(A.root[x],1,n,v[x][i].l,r-1));
    	}
    }
    void solve1(int x,int len)
    {
    	if(P.id[x]) B.change(B.root,1,n,P.id[x],P.id[x]-len);
    	for(int i=head[x];i;i=nxt[i]) solve1(ver[i],len);
    }
    void solve(int x)
    {
    	for(int i=x;i;i=son[i]){
    		for(int j=head[i];j;j=nxt[j]){
    			if(ver[j]!=son[i]) solve(ver[j]);
    		}
    	}
    	B.clear();
    	for(int i=x;i;i=son[i]){
    		for(int j=head[i];j;j=nxt[j]){
    			if(ver[j]!=son[i]) solve1(ver[j],P.t[i].len);
    		}
    		if(P.id[i]) B.change(B.root,1,n,P.id[i],P.id[i]-P.t[i].len);
    		for(int j=0;j<v[i].size();j++){
    			ans[v[i][j].id]=max(ans[v[i][j].id],B.ask(B.root,1,n,v[i][j].l,v[i][j].r-1,v[i][j].l));
    		}
    	}
    }
    int main()
    {
    	P.cnt=P.last=1;B.t[0].dat=1<<30;
    	scanf("%s",s+1);
    	n=strlen(s+1);
    	for(i=1;i<=n;i++) P.extend(s[i],i);
    	for(i=2;i<=P.cnt;i++) insert(P.t[i].link,i);
    	scanf("%d",&m);
    	dfs1(1,0);dfs2(1,1);
    	for(i=1;i<=m;i++){
    		int l,r,x;
    		scanf("%d%d",&l,&r);
    		x=P.pos[r];a[i].l=l;a[i].r=r;
    		while(x){
    			v[x].push_back(query(l,r,i));
    			x=fa[top[x]];
    		}
    	}
    	dfs(1);
    	solve(1);
    	for(i=1;i<=m;i++){
    		if(ans[i]==0) puts("0");
    		else printf("%d
    ",ans[i]-a[i].l+1);
    	}
    	return 0;
    }
    
  • 相关阅读:
    html转义
    mongodb 数据库 基础使用
    xpath基本语法
    HTTP
    JavaScript笔记6-数组新方法
    JavaScript笔记5-事件
    JavaScript笔记3--标识符和保留字
    JavaScript笔记4-数组
    jquery笔记1--选择器
    JavaScript笔记2
  • 原文地址:https://www.cnblogs.com/LSlzf/p/14386036.html
Copyright © 2020-2023  润新知