zoukankan      html  css  js  c++  java
  • 【loj6198】谢特

    Portal -->loj6198

    Solution

    ​  (为什么感觉loj上面这几道后缀数组的题。。套路都是一样的啊qwq)

    ​  同样也是。。考虑某个区间(height[i])的最小值的贡献

    ​​  记(solve(i,j))表示统计(rk)(in [l,r])的后缀对答案的贡献,那么我们有一个十分简单粗暴的想法,我们用ST表求出([l,r])区间内的(height)最小值(x),记它的位置为(mid),如果说一开始我们先按照(rk)的顺序建一棵可持久化trie,那么这个时候我们就可以直接枚举(rk)(in [l,mid-1])区间的后缀的(w),然后在([mid,r])的区间内的trie上查(w)的最大异或值就好了

    ​​  但是现在的问题是,这样显然会超时

    ​  这里我们其实可以用一个。。类似启发式合并的思想,我们每次比较([l,mid-1])([mid,r])这两个区间谁比较短,然后我们就枚举较短的区间内的(w)值,在另一个区间的trie上查然后更新

    ​  这样的复杂度我不太会证qwq但是能够过掉qwq

    ​​  然后可能因为我的递归写的太挫了要手动扩栈才能愉快AC菜醒qwq

    ​  

    ​  代码大概长这个样子

    #pragma comment(linker,"/STACK:102400000,102400000")
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #define mp make_pair
    #define Pr pair<int,int>
    #define ll long long
    using namespace std;
    const int N=1e5+10,TOP=16;
    char s[N];
    int w[N];
    int n;
    ll ans,Cnt;
    namespace Trie{/*{{{*/
    	int ch[N*2*30][2],cnt[N*2*30],rt[N];
    	int tot;
    	int newnode(int x){
    		ch[++tot][0]=ch[x][0]; ch[tot][1]=ch[x][1];cnt[tot]=cnt[x];
    		return tot;
    	}
    	void _insert(int x,int &now,int delta,int d){
    		now=newnode(x);
    		++cnt[now];
    		if (d<0) return;
    		int which=delta>>d&1;
    		_insert(ch[x][which],ch[now][which],delta,d-1);
    	}
    	void insert(int x,int delta){_insert(!x?0:rt[x-1],rt[x],delta,TOP);}
    	int _get_mx(int l,int r,int delta,int d){
    		if (d<0) return 0;
    		int which=delta>>d&1;
    		if (cnt[ch[r][which^1]]-cnt[ch[l][which^1]]) 
    			return _get_mx(ch[l][which^1],ch[r][which^1],delta,d-1)+(1<<d);
    		return _get_mx(ch[l][which],ch[r][which],delta,d-1);
    	}
    	int get_mx(int l,int r,int delta){
    		if (l==-1||r==-1) return 0;
    		return _get_mx(rt[l-1],rt[r],delta,TOP);
    	}
    }/*}}}*/
    namespace Sa{/*{{{*/
    	int a[N],b[N],c[N],sa[N],height[N],rk[N];
    	int mn[N][TOP+1],loc[N][TOP+1];
    	int mx;
    	bool cmp(int x,int y,int len,int *r)
    	{return r[x]==r[y]&&r[x+len]==r[y+len];}
    	void sort(int n){
    		for (int i=0;i<=mx;++i) c[i]=0;
    		for (int i=1;i<=n;++i) ++c[a[b[i]]];
    		for (int i=1;i<=mx;++i) c[i]+=c[i-1];
    		for (int i=n;i>=1;--i) sa[c[a[b[i]]]--]=b[i];
    	}
    	void get_sa(int n){
    		int cnt=0; mx=0;
    		for (int i=1;i<=n;++i) a[i]=s[i]-'a'+1,b[i]=i,mx=max(mx,a[i]);
    		sort(n);
    		for (int len=1;cnt<n;len<<=1){
    			cnt=0;
    			for (int i=n-len+1;i<=n;++i) b[++cnt]=i;
    			for (int i=1;i<=n;++i)
    				if (sa[i]>len)
    					b[++cnt]=sa[i]-len;
    			sort(n);
    			swap(a,b);
    			cnt=1; a[sa[1]]=1;
    			for (int i=2;i<=n;a[sa[i++]]=cnt)
    				if (!cmp(sa[i-1],sa[i],len,b)) ++cnt;
    			mx=cnt;
    		}
    	}
    	void rmq(){
    		for (int i=1;i<=n;++i) mn[i][0]=height[i],loc[i][0]=i;
    		for (int j=1;j<=TOP;++j)
    			for (int i=n-(1<<j)+1;i>=1;--i)
    				if (mn[i][j-1]<mn[i+(1<<j-1)][j-1])
    					mn[i][j]=mn[i][j-1],loc[i][j]=loc[i][j-1];
    				else
    					mn[i][j]=mn[i+(1<<j-1)][j-1],loc[i][j]=loc[i+(1<<j-1)][j-1];
    	}
    	Pr get_lcp(int x,int y){//ranks
    		if (x==y) return mp(n-sa[x]+1,x);
    		if (x>y) swap(x,y);
    		++x;
    		int len=y-x+1,lg=(int)(log(1.0*len)/log(2.0));
    		if (mn[x][lg]<mn[y-(1<<lg)+1][lg])
    			return mp(mn[x][lg],loc[x][lg]);
    		else
    			return mp(mn[y-(1<<lg)+1][lg],loc[y-(1<<lg)+1][lg]);
    	}
    	void get_height(int n){
    		for (int i=1;i<=n;++i) rk[sa[i]]=i;
    		int k=0;
    		for (int i=1;i<=n;++i){
    			if (k) --k;
    			while (s[i+k]==s[sa[rk[i]-1]+k]) ++k;
    			height[rk[i]]=k;
    		}
    		rmq();
    	}
    	void solve(int l,int r){
    		if (l>=r) return;
    		Pr tmp=get_lcp(l,r);
    		int mid=tmp.second,lcp=tmp.first;
    		if (r-mid+1<mid-1-l+1){
    			for (int i=mid;i<=r;++i)
    				ans=max(ans,1LL*lcp+Trie::get_mx(l,mid-1,w[sa[i]]));
    		}
    		else{
    			for (int i=l;i<=mid-1;++i)
    				ans=max(ans,1LL*lcp+Trie::get_mx(mid,r,w[sa[i]]));
    		}
    		solve(l,mid-1);
    		solve(mid,r);
    	}
    }/*}}}*/
    
    int main(){
    #ifndef ONLINE_JUDGE
    	freopen("a.in","r",stdin);
    #endif
    	scanf("%d",&n);
    	scanf("%s",s+1);
    	for (int i=1;i<=n;++i) scanf("%d",w+i);
    	Sa::get_sa(n);
    	Sa::get_height(n);
    	//for (int i=1;i<=n;++i) printf("%d ",Sa::sa[i]); printf("
    ");
    	for (int i=1;i<=n;++i)
    		Trie::insert(i,w[Sa::sa[i]]);
    	ans=0;
    	Sa::solve(1,n);
    	printf("%lld
    ",ans);
    }
    
  • 相关阅读:
    html表单
    html基础
    MySQL数据库 数据的更新
    JAVA数据库编程
    集合框架
    线程和进程
    反射
    centos 7环境
    js中的this
    javascript的作用域以及闭包现象
  • 原文地址:https://www.cnblogs.com/yoyoball/p/9373116.html
Copyright © 2011-2022 走看看