1. 程式人生 > >51nod 1485字母排序

51nod 1485字母排序

這題目的原題是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(我絕對不是在賣廣告,裡面都是大神。)