1. 程式人生 > >【2018/10/16測試T3】長者

【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;
}