1. 程式人生 > >NOIP提高模擬-20181016-T3-長者

NOIP提高模擬-20181016-T3-長者

寫在前面

考場上看到本題根本不會,下來以後看了看題解發現是一道主席樹+hash的題目,然而完全不會,所以說去認真的學習了主席樹之後,成功的A掉了這道題目。

Solution

10pts10pts做法

按照題目存下所有長者對應的字串,然後暴力比較兩個字串的大小,快速排序即可。 時間複雜度 O(n2logn)O(n^2logn)

30pts30pts做法

可以利用雜湊做到O(logn)O(logn)比較兩個字串的大小。 具體方法是雜湊結合二分找到第一個字串不同的位置,然後比較這個位置的大小。 結合快速排序,時間複雜度O(n2+nlog2n)O(n^2+nlog^2n)

對於另外30pts30pts

pi=i+12 \because p_i=⌊\frac{i+1}{2}⌋\qquad \therefore 此時形成一棵二叉樹,任意長者的字串與 1 號長者的字串最多隻有 O(logn)O(logn)處不同。這 說明任意兩個字串最多也只有 O(logn)O(logn) 處不同。

於是我們只用比較這 O(logn)O(logn)個不同的位置,結合快速排序可以做到 O(nlog2n)O(nlog^2n)

100pts100pts做法

雜湊二分的方法其實就是不斷的詢問字串的某一部分的雜湊值。

我們可以用線段樹來維護雜湊值,那麼每次修改一個位置只需要把父親的線段樹改一個位置。 利用主席樹來維護,比較的時候也從主席樹的兩個根開始遞迴比較,可以做到 O(nlog2n)O(nlog^2n)。 Talk is Cheap, Show You the Code:

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ULL;
int read(){
	int sum=0,neg=1;
	char c=getchar();
	while(c>'9'||c<'0'&&
c!='-') c=getchar(); if(c=='-') neg=-1,c=getchar(); while(c>='0'&&c<='9') sum=(sum<<1)+(sum<<3)+c-'0',c=getchar(); return sum*neg; } const int N=1e5+50; const ULL base=31; int n,m; char s[N]; int rt[N],lc[N*40],rc[N*40],len[N*40],p[N],tot; ULL pw[N],sum[N*40]; inline void build(int &k,int l,int r){ k=++tot; len[k]=r-l+1; if(l==r) {sum[k]=s[l]; return;} int mid=(l+r)>>1; build(lc[k],l,mid); build(rc[k],mid+1,r); sum[k]=sum[lc[k]]+sum[rc[k]]*pw[len[lc[k]]]; } inline void copy(int &x,int y){ x=++tot; lc[x]=lc[y]; rc[x]=rc[y]; len[x]=len[y]; sum[x]=sum[y]; } inline void inc(int x,int &y,int l,int r,int p,int v){ copy(y,x); if(l==r){ sum[y]=v; return; } int mid=(l+r)>>1; if(p<=mid) inc(lc[x],lc[y],l,mid,p,v); else inc(rc[x],rc[y],mid+1,r,p,v); sum[y]=sum[lc[y]]+sum[rc[y]]*pw[len[lc[y]]]; } inline int cmp(int x,int y,int l,int r){ if(l==r){ return (sum[x]<sum[y])?-1:1; } int mid=(l+r)>>1; if(sum[lc[x]]!=sum[lc[y]]) return cmp(lc[x],lc[y],l,mid); else return cmp(rc[x],rc[y],mid+1,r); } inline bool comp(const int &i,const int &j){ if(sum[rt[i]]==sum[rt[j]]) return i<j; return cmp(rt[i],rt[j],1,m)<0; } int main(){ n=read(), m=read(); scanf("%s",s+1); for(int i=pw[0]=1;i<=m;++i) pw[i]=pw[i-1]*base; build(rt[1],1,m); for(int i=2;i<=n;i++){ int f=read(), pos=read(); scanf("%s",s+1); inc(rt[f],rt[i],1,m,pos,s[1]); } for(int i=1;i<=n;i++) p[i]=i; sort(p+1,p+n+1,comp); for(int i=1;i<=n;i++) printf("%d ",p[i]); }