【2018/10/16测试T3】长者

【题目】

内网传送门
外网传送门

【分析】

30 pts:哈希+二分

可以用 s t r i n g string 排序,也可以利用哈希做到 O ( l o g    n ) (log\;n) 比较两个字符串的大小。

具体方法是哈希结合二分找到第一个字符串不同的位置,然后比较这个位置的大小。

结合 s o r t sort ,时间复杂度O ( n 2 + n l o g 2 n ) (n^2+n*log^2n)

另外 30 pts( p i = i + 1 2 p_i=⌊\frac{i+1}2⌋ ):二叉树

此时形成一棵二叉树,任意长者的字符串与 1 1 号长者的字符串最多只有 O ( l o g    n ) (log\;n) 处不同。这说明任意两个字符串最多也只有 O ( l o g    n ) (log\;n) 处不同。

于是我们只用比较这 O ( l o g n ) (logn) 个不同的位置,结合 s o r t sort 可以做到 O ( n l o g 2 n ) (n*log^2n)

100 pts:主席树

哈希二分的方法其实就是不断的询问字符串的某一部分的哈希值。

我们可以用线段树来维护哈希值,那么每次修改一个位置只需要把父亲的线段树改一个位置。 利用主席树来维护,比较的时候也从主席树的两个根开始递归比较,可以做到 O ( n l o g 2 n ) (n*log^2n)

这里解释一点:代码中线段树在合并哈希值时是倒着合并的,即若左子树是 a a ,右子树是 b b ,那合并上来应该是 b a ba ,但这不影响答案的正确性,因为哈希只是判断两个串是否相等,比较时还是要递归到叶子才 r e t u r n return (改成正着合并也可以)

【代码】

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
#define LogN 40
#define base 31
#define ull unsigned long long
using namespace std;
int n,m,t;
char s[N];
ull Pow[N]={1};
int rank[N],root[N];
struct President_Tree
{
	ull num;
	int lc,rc,len;
	#define lc(x) a[x].lc
	#define rc(x) a[x].rc
	#define len(x) a[x].len
	#define num(x) a[x].num
}a[N*LogN];
void build(int &root,int l,int r)
{
	root=++t;
	len(root)=r-l+1;
	if(l==r)
	{
		num(root)=s[l];
		return;
	}
	int mid=(l+r)>>1;
	build(lc(root),l,mid);
	build(rc(root),mid+1,r);
	num(root)=num(lc(root))+num(rc(root))*Pow[len(lc(root))];
}
void insert(int y,int &x,int l,int r,int pos,char c)
{
	x=++t;
	a[x]=a[y];
	if(l==r)
	{
		num(x)=c;
		return;
	}
	int mid=(l+r)>>1;
	if(pos<=mid)  insert(lc(y),lc(x),l,mid,pos,c);
	else  insert(rc(y),rc(x),mid+1,r,pos,c);
	num(x)=num(lc(x))+num(rc(x))*Pow[len(lc(x))];
}
int cmp(int x,int y,int l,int r)
{
	if(l==r)
	  return num(x)<num(y)?-1:1;
	int mid=(l+r)>>1;
	if(num(lc(x))!=num(lc(y)))
	  return cmp(lc(x),lc(y),l,mid);
	return cmp(rc(x),rc(y),mid+1,r);
}
bool comp(const int &p,const int &q)
{
	if(num(root[p])!=num(root[q]))
	  return cmp(root[p],root[q],1,m)<0;
	return p<q;
}
int main()
{
//	freopen("z.in","r",stdin);
//	freopen("z.out","w",stdout);
	int p,pos,i;
	scanf("%d%d%s",&n,&m,s+1);
	for(i=1;i<=m;++i)
	  Pow[i]=Pow[i-1]*base;
	build(root[1],1,m);
	for(i=2;i<=n;++i)
	{
		scanf("%d%d%s",&p,&pos,s+1);
		insert(root[p],root[i],1,m,pos,s[1]);
	}
	for(i=1;i<=n;++i)  rank[i]=i;
	sort(rank+1,rank+n+1,comp);
	for(i=1;i<=n;++i)  printf("%d ",rank[i]);
//	fclose(stdin);
//	fclose(stdout);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/forever_dreams/article/details/83095346
今日推荐