51nod 1485字母排序
阿新 • • 發佈:2019-02-06
這題目的原題是CF 558E但是加強了。
問題非常簡單,給定一個長度為n的字串S,有q個操作,每次操作的形式為 i j k,表示對從i到j的這一段子串進行排序,如果k=1進行非降序排序,否則進行非升序排序。
輸出最後的字串。
樣例解釋:
Input
單組測試資料。
第一行有兩個整數n, q (1 ≤ n ≤ 10^5, 0 ≤ q ≤ 50 000),表示字串的長度和操作次數。
第二行有一個字串。只由小寫字母組成。
接下來q行,每行包含三個整數 i,j,k(1 ≤ i ≤ j ≤ n, k∈{0,1})。
Output
輸出最後的字串。
Input示例
10 5
abacdabcda
7 10 0
5 8 1
1 4 0
3 6 0
7 10 1
Output示例
cbcaaaabdd
這道題有兩種演算法,一種是splay維護,比較複雜但是跑的飛快,另一種就是26棵線段樹直接莽一波,比較暴力而且簡單,就是細節比較複雜。
線段樹維護的是:26個字母中排第i個的字母在各個區間的數目。
這樣一來,我們就可以將一個字串S完美的融入到這26棵線段樹中去,更新和查詢都從上面的O(n)變為了O(logn)。
下面貼出核心程式碼:
int main()
{
int i,j,k;
scanf("%d%d",&n,&q);
scanf("%s",s);
for(i=0;i<q;i++)
scanf("%d%d%d",&l[i],&r[i],&c[i]);
memset(a,-1,sizeof(a));
for(i=1;i<26;i++)
{
build(1,n,i,1);
for(j=0;j<q;j++)
{
k=qz(1 ,n,l[j],r[j],1);
if(c[j])
{
update(1,n,l[j],r[j]-k,0,1);
update(1,n,r[j]-k+1,r[j],1,1);
}
else
{
update(1,n,l[j],l[j]+k-1,1,1);
update(1,n,l[j]+k,r[j],0,1);
}
}
for (j=0;j<n;j++)
{
k=query(1,n,j+1,1);
if(!k&&a[j]==-1)
a[j]='a'+i-1;
}
}
for(j=0;j<n;j++)
{
if(a[j]==-1)
a[j]='z';
}
a[n]=0;
printf("%s\n",a);
return 0;
}
剩餘的都是一些線段樹的操作,例如釋放標記啊之類的,主要就是這裡了吧。
想知道splay怎麼做的加51nod的Q群251587768(我絕對不是在賣廣告,裡面都是大神。)