zoukankan      html  css  js  c++  java
  • LOJ 6041 事情的相似度

    LOJ 6041 事情的相似度

    题目描述

    人的一生不仅要靠自我奋斗,还要考虑到历史的行程。

    历史的行程可以抽象成一个 01 串,作为一个年纪比较大的人,你希望从历史的行程中获得一些姿势。

    你发现在历史的不同时刻,不断的有相同的事情发生。比如,有两个人同时在世纪之交 11 年的时候上台,同样喜欢与洋人谈笑风生,同样提出了以「三」字开头的理论。

    你发现,一件事情可以看成是这个 01 串的一个前缀,这个前缀最右边的位置就是这个事情的结束时间。

    两件事情的相似度可以看成,这两个前缀的最长公共后缀长度。

    现在你很好奇,在一段区间内结束的事情中最相似的两件事情的相似度是多少呢?

    数据范围:(n,mle 10^5)

    思路

    首先,建一个后缀自动机。

    那么,两件事情的相似度就是他们(parent)树上的最近公共祖先的深度。

    我们考虑把所有询问离线下来,按照右端点排序。

    那么,每次查询时,我们只需要知道([l,r])中每个点到他后面的点的贡献,再取(max)即可

    我们考虑,每次加入一个点的时候,把这个点到根的路径全部染上他的颜色。

    每遇见一种颜色时,更新这个颜色的答案。

    首先发现,如此操作与我们理论上要求的略有不同,因为后面的颜色会覆盖前面的颜色,就导致前面的颜色的答案并没有更新。

    但是再仔细想想,这对答案并不影响。因为我们是从前到后把点加进来的,所以说如果你能覆盖前面的颜色,也一定能覆盖后面的颜色。

    于是我们用类似(LCT)(access)操作维护即可。

    代码

    #include<bits/stdc++.h>
    #define lch ch[x][0]
    #define rch ch[x][1]
    #define now c[top].nxt[k]
    using namespace std;
    const int sz=2e5+7;
    int n,m;
    int cnt,L,R;
    int rt,lst,cur,top;
    int f[sz],col[sz];
    int pos[sz];
    int mx[sz],ans[sz];
    int ch[sz][2];
    char s[sz];
    struct node{
    	int len,link,nxt[2];
    }c[sz];
    struct Que{
    	int l,r,id;
    	const bool operator <(const Que &p)const{
    		return r<p.r;
    	}
    }q[sz];
    void update(int x,int sum){
    	for(;x;x-=x&-x) mx[x]=max(mx[x],sum);
    }
    int query(int x){
    	int ret=0;
    	for(;x<=n;x+=x&-x) ret=max(ret,mx[x]);
    	return ret;
    }
    bool nroot(int x){
    	return ch[f[x]][0]==x||ch[f[x]][1]==x;
    }
    int get(int x){
    	return ch[f[x]][1]==x;
    }
    void pushdn(int x){
    	if(lch) col[lch]=col[x];
    	if(rch) col[rch]=col[x];
    }
    void pushall(int x){
    	if(nroot(x)) pushall(f[x]);
    	pushdn(x);
    }
    void rotate(int x){
    	int y=f[x],z=f[y],k=get(x),w=ch[x][!k];
    	if(nroot(y)) ch[z][get(y)]=x;ch[x][!k]=y;ch[y][k]=w;
    	if(w) f[w]=y;f[y]=x;f[x]=z;
    }
    void splay(int x){
    	pushall(x);
    	for(int y;nroot(x);rotate(x)) if(nroot(y=f[x])) rotate(get(x)^get(y)?x:y);
    }
    void access(int x,int cc){
    	for(int y=0;x;x=f[y=x]){
    		splay(x);
    		update(col[x],c[x].len);
    		col[x]=cc;
    		rch=y;
    	}
    }
    void insert(int k){
    	cur=++cnt;
    	c[cur].len=c[lst].len+1;
    	pos[c[cur].len]=cur;
    	top=lst;
    	lst=cur;
    	for(;top&&!now;top=c[top].link) now=cur;
    	if(!top) return (void)(c[cur].link=rt);
    	if(c[top].len+1==c[now].len) return (void)(c[cur].link=now);
    	int p=++cnt,np=now;
    	c[p]=c[np];
    	c[p].len=c[top].len+1;
    	c[np].link=c[cur].link=p;
    	for(;top&&now==np;top=c[top].link) now=p; 
    }
    void build(){
    	for(int i=cnt;i>=2;i--) f[i]=c[i].link;
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	scanf("%s",s+1);
    	rt=lst=++cnt;
    	for(int i=1;i<=n;i++) insert(s[i]-'0');
    	build();
    	for(int i=1;i<=m;i++){
    		scanf("%d%d",&L,&R);
    		q[i]=(Que){L,R,i};
    	}
    	sort(q+1,q+m+1);
    	int tot=0;
    	for(int i=1;i<=m;i++){
    		while(tot<q[i].r){
    			tot++;
    			access(pos[tot],tot);
    		}
    		ans[q[i].id]=query(q[i].l);
    	}
    	for(int i=1;i<=m;i++) printf("%d
    ",ans[i]);
    } 
    
  • 相关阅读:
    三数之和
    罗马数字与整数
    Oracle 开启或关闭归档
    Oracle RMAN scripts to delete archivelog
    Oracle check TBS usage
    Oracle kill locked sessions
    场景9 深入RAC运行原理
    场景7 Data Guard
    场景4 Data Warehouse Management 数据仓库
    场景5 Performance Management
  • 原文地址:https://www.cnblogs.com/river-flows-in-you/p/11974579.html
Copyright © 2011-2022 走看看