2018.9.22 ACM训练 CCPC北京 online

网络赛的画风都略有奇怪
但是我们发挥的更差了
话说网络赛没有题解真是气人!

题目

I 是道好题,但是莫名奇妙T了
给出一些子串,求将它们顺次排列后序列,使相邻串lcp的字典序。
做法: 后缀树+虚树+树形dp
考场上没有想到dp的思想把每个子树中的序列按字典序排序后合并起来。分隔符是这个点的val。启发式合并保证复杂度。
当时写的奇奇怪怪的贪心细节很多没有考虑全面,调了很久也没有调出来。

把代码粘出来留坑。有两个问题:1. 可能是vec开得太多。不知道为什么超级慢,把maxn一开大就会慢
2. 在后缀树上定位串需要倍增,不能直接暴力跳

#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define per(i,a,b) for(int i=a;i>=b;--i)
#define rvc(i,S) for(int i=0;i<(int)S.size();++i)
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define debug(...) fprintf(stderr,__VA_ARGS__)
using namespace std;
#define inf 0x3f3f3f3f
#define maxn 4020

struct node{
	int next,to;
}e[maxn];

int head[maxn],cnt,tot;
int id[maxn],sz[maxn],fa[maxn],mn[21][maxn * 2],num[maxn * 2],a[maxn * 2],dfstime,dth[maxn],dfn[maxn],len[maxn],pnt[maxn];
int stack_[maxn],tops,rec,rt,tag[maxn];
int n,m,T;
char ch[maxn];
vector <int> vec[maxn],son[maxn],ans,dt[maxn],p;

inline void adde(int x,int y){
	e[++cnt].to = y;
	e[cnt].next = head[x];
	head[x] = cnt;
}
struct SAM{
	int next[maxn][26],val[maxn],pnt[maxn],last,tot;
	void clear(){
		rep(i,0,tot) memset(next,0,sizeof(next)) , val[i] = pnt[i] = 0;
		tot = last = 0;
	}
	void Add(int x){
		int p = last , np = ++tot;
		val[np] = val[p] + 1 , id[val[np]] = tot + 1;
		while ( !next[p][x] && p ) next[p][x] = np , p = pnt[p];
		int q = next[p][x];
		if ( !q ) next[p][x] = np , pnt[np] = p;
		else if ( val[p] + 1 == val[q] ) pnt[np] = q;
		else{
			int nq = ++tot;
			val[nq] = val[p] + 1;
			pnt[nq] = pnt[q];
			pnt[np] = pnt[q] = nq;
			memcpy(next[nq],next[q],sizeof(next[q]));
			while ( p && next[p][x] == q ) next[p][x] = nq , p = pnt[p];
			if ( next[p][x] == q ) next[p][x] = nq;
		}
		last = np;
	}
	void pre(){
		rep(i,1,tot + 1) head[i] = 0;
		cnt = 0;
		rep(i,1,tot) adde(pnt[i] + 1,i + 1) , len[i + 1] = val[i];
	}
	void print(){
		rep(i,1,tot) cout<<i + 1<<" "<<pnt[i] + 1<<endl;
	}
}sam;


void clear(){
	sam.clear();
	cnt = tot = 0;
}
void clear2(){
	cnt = 0;
	tops = 0;
	p.clear();
}

inline bool cmp(int x,int y){ return dfn[x] < dfn[y]; }

void dfs(int x){
	a[++tot] = x , dfn[x] = tot;
	for (int &i = head[x] ; i ; i = e[i].next){
		pnt[e[i].to] = x , dth[e[i].to] = dth[x] + 1;
		dfs(e[i].to);
		a[++tot] = x;
	}
}
void Init_Tree(){
	dfs(1);
	rep(i,1,tot){
		num[i] = num[i - 1];
		if ( (1 << (num[i] + 1)) < i ) num[i]++;
	}		
	rep(i,1,tot) mn[0][i] = a[i];
	rep(i,1,20){
		rep(j,1,tot){
			if ( j + (1 << (i - 1)) > tot || dth[mn[i - 1][j]] < dth[mn[i - 1][j + (1 << (i - 1))]] ) 
				mn[i][j] = mn[i - 1][j];
			else 
				mn[i][j] = mn[i - 1][j + (1 << (i -1))];
		}
	}
}

void init(){
	rep(i,1,n) sam.Add(ch[i] - 'a');
	sam.pre();
	Init_Tree();
//	sam.print();
}
inline int lca(int x,int y){
	int l = dfn[x] , r = dfn[y];
	if ( l > r ) swap(l,r);
	int len = r - l + 1,c = num[len],id1 = mn[c][l],id2 = mn[c][r - (1 << c) + 1];
	if ( dth[id1] < dth[id2] ) return id1;
	return id2;
}
void insert(int x){
	if ( !tops ){ stack_[++tops] = x; return; }
	int v = stack_[tops] , lca_ = lca(v,x) , w = stack_[tops - 1];
	while ( tops > 1 && dth[w] > dth[lca_] ){
		adde(w,v);
		tops--;
		v = w;
		w = stack_[tops - 1];
	}
	if ( v != lca_ ){
		adde(lca_,v) , tops--;
		if ( stack_[tops] != lca_ ) stack_[++tops] = lca_;
	}
	stack_[++tops] = x;
}

inline bool cmp2(int x,int y){
	if ( !vec[x].size() ) return 0;
	if ( !vec[y].size() ) return 1;
	rep(i,0,min(vec[x].size(),vec[y].size()) - 1) if ( vec[x][i] != vec[y][i] ) return vec[x][i] > vec[y][i];
	return vec[x].size() > vec[y].size();
}	
inline void merge(int x,int y){
	if ( vec[x].size() > vec[y].size() ){
		rvc(i,vec[y]) vec[x].pb(vec[y][i]);
	}
	else{
		rvc(i,vec[x]) vec[y].pb(vec[x][i]);
		//vec[x].begin() = vec[y].begin();
		//vec[x].swap(vec[y]);
		swap(vec[x],vec[y]);
	}
}
void dfs2(int x){
	for (int i = head[x] ; i ; i = e[i].next){
		dfs2(e[i].to);
		if ( sz[e[i].to] ) son[x].pb(e[i].to);
		sz[x] += sz[e[i].to];
	}	
	sort(son[x].begin(),son[x].end(),cmp2);
	rvc(i,son[x]){
		merge(x,son[x][i]);
		if ( i < (int)son[x].size() - 1 ) vec[x].pb(len[x]);
	}
	if ( dt[x].size() && son[x].size() ) vec[x].pb(dt[x].back());
	while ( dt[x].size() > 1 ) vec[x].pb(dt[x][dt[x].size() - 2]) , dt[x].pop_back(); 
}
void dfs_c(int x){
	vec[x].clear() , dt[x].clear() , son[x].clear();
	sz[x] = 0;
	for (int &i = head[x] ; i ; i = e[i].next){
		fa[e[i].to] = 0;
		dfs_c(e[i].to);
	}
}

void solve(){
	dfs_c(rt);
	clear2();
	int t,l,r,clen,cur;
	scanf("%d",&t);
	rep(i,1,t){
		scanf("%d %d",&l,&r) , l++ , r++;
		clen = r - l + 1 , l = n - l + 1;
		cur = id[l];
		while ( clen <= len[pnt[cur]] ) cur = pnt[cur];
		sz[cur]++ , p.pb(cur) , dt[cur].pb(clen);
	}
	sort(p.begin(),p.end(),cmp);
	p.erase(unique(p.begin(),p.end()),p.end());
	rvc(i,p) insert(p[i]);
//	rvc(i,p) cout<<p[i]<<" ";
//	cout<<endl;
	while ( tops > 1 ) adde(stack_[tops - 1],stack_[tops]) , tops--;
	rt = stack_[1];
	dfs2(rt);
	
	rvc(i,vec[rt]){
		printf("%d",vec[rt][i]);
		if ( i < vec[rt].size() - 1 ) printf(" ");
		else printf("\n");
	}

}
int main(){
	freopen("input.txt","r",stdin);
	scanf("%d",&T);
	rep(t,1,T){
		printf("Case %d:\n",t);
		clear();
		scanf("%d %d",&n,&m);
		scanf("%s",ch + 1);
		reverse(ch + 1,ch + n + 1);
		init();
		while ( m-- ){
			solve();
		}	
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值