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

    Description

    人的一生不仅要靠自我奋斗,还要考虑到历史的行程。
    历史的行程可以抽象成一个 01 串,作为一个年纪比较大的人,你希望从历史的行程中获得一些姿势。
    你发现在历史的不同时刻,不断的有相同的事情发生。比如,有两个人同时在世纪之交 11 年的时候上台,同样喜欢与洋人谈笑风生,同样提出了以「三」字开头的理论。
    你发现,一件事情可以看成是这个 01 串的一个前缀,这个前缀最右边的位置就是这个事情的结束时间。
    两件事情的相似度可以看成,这两个前缀的最长公共后缀长度。
    现在你很好奇,在一段区间内结束的事情中最相似的两件事情的相似度是多少呢?

    Solution

    考虑暴力做法,离线询问
    因为两个串的最长公共后缀,就是所代表节点的 (lca)(len)
    每一次加入一个前缀,在 (parent) 树上往上跳,如果一个点被跳过我们就更新答案
    因为右端点固定时,左端点越大,对询问的贡献肯定越多,所以直接覆盖掉这个节点事件的下标(也就是 (pos)),所以我们维护这个节点子树内的最大 (pos) 值就行了
    但是还有一个左端点限制,我们开一个左端点为下标的树状数组维护一下就好了
    实际上这个过程就是 (LCT)(access),那么用 (LCT) 做这个过程复杂度就可以均摊为 (access) 的复杂度了

    #include<bits/stdc++.h>
    using namespace std;
    const int N=2e5+10;
    template<class T>void gi(T &x){
    	int f;char c;
    	for(f=1,c=getchar();c<'0'||c>'9';c=getchar())if(c=='-')f=-1;
    	for(x=0;c>='0'&&c<='9';c=getchar())x=x*10+(c&15);x*=f;
    }
    int fa[N],ch[N][2],len[N],cur=1,cnt=1,n,Q,pos[N];
    char s[N];int tr[N],ans[N];
    struct data{int x,id;};
    vector<data>v[N];vector<data>::iterator it;
    inline void add(int x,int y){for(int i=x;i>=1;i-=(i&(-i)))tr[i]=max(tr[i],y);}
    inline int qry(int x){
    	int ret=0;
    	for(int i=x;i<=n;i+=(i&(-i)))ret=max(ret,tr[i]);
    	return ret;
    }
    namespace lct{
    	int fa[N],ch[N][2],w[N],la[N];
    	inline void mark(int x,int y){w[x]=y;la[x]=y;}
    	inline bool isrt(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
    	inline void rotate(int x){
    		int y=fa[x];bool t=ch[y][1]==x;
    		ch[y][t]=ch[x][!t];fa[ch[y][t]]=y;
    		ch[x][!t]=y;fa[x]=fa[y];
    		if(!isrt(y))ch[fa[y]][ch[fa[y]][1]==y]=x;
    		fa[y]=x;
    	}
    	inline void pushdown(int x){
    		if(!la[x])return ;
    		mark(ch[x][0],la[x]);mark(ch[x][1],la[x]);la[x]=0;
    	}
    	inline void Push(int x){if(!isrt(x))Push(fa[x]);pushdown(x);}
    	inline void splay(int x){
    		Push(x);
    		while(!isrt(x)){
    			int y=fa[x],p=fa[y];
    			if(isrt(y))rotate(x);
    			else if((ch[p][0]==y)==(ch[y][0]==x))rotate(y),rotate(x);
    			else rotate(x),rotate(x);
    		}
    	}
    	inline void access(int x,int id){
    		int y=0;
    		while(x)splay(x),ch[x][1]=y,add(w[x],len[x]),x=fa[y=x];
    		mark(y,id);
    	}
    }
    inline void ins(int c){
    	int p=cur;cur=++cnt;len[cur]=len[p]+1;
    	for(;p && !ch[p][c];p=fa[p])ch[p][c]=cur;
    	if(!p)fa[cur]=1;
    	else{
    		int q=ch[p][c];
    		if(len[p]+1==len[q])fa[cur]=q;
    		else{
    			int nt=++cnt;len[nt]=len[p]+1;
    			memcpy(ch[nt],ch[q],sizeof(ch[q]));
    			fa[nt]=fa[q];fa[cur]=fa[q]=nt;
    			for(;p && ch[p][c]==q;p=fa[p])ch[p][c]=nt;
    		}
    	}
    }
    int main(){
      freopen("pp.in","r",stdin);
      freopen("pp.out","w",stdout);
      int x,y;
      cin>>n>>Q;
      scanf("%s",s+1);
      for(int i=1;i<=n;i++)ins(s[i]-'0'),pos[i]=cur;
      for(int i=1;i<=Q;i++)gi(x),gi(y),v[y].push_back((data){x,i});
      for(int i=2;i<=cnt;i++)lct::fa[i]=fa[i];
      for(int i=1;i<=n;i++){
    	  lct::access(pos[i],i);
    	  for(it=v[i].begin();it!=v[i].end();++it)ans[it->id]=qry(it->x);
      }
      for(int i=1;i<=Q;i++)printf("%d
    ",ans[i]);
      return 0;
    }
    
    
  • 相关阅读:
    Qt 多线程使用moveToThread
    FFmpeg下载地址
    选择排序
    数据结构和算法之时间复杂度和空间复杂度
    嵌入式动态库查看需要的依赖库
    Q_UNUSED 的使用
    php对csv文件的读取,写入,输出下载操作
    python一个简单的登录
    python的反射
    python类的特性
  • 原文地址:https://www.cnblogs.com/Yuzao/p/8902237.html
Copyright © 2011-2022 走看看