1. 程式人生 > >2018.08.18【2018提高組】模擬A組題解(JZOJ5829)string

2018.08.18【2018提高組】模擬A組題解(JZOJ5829)string

T1:

5831.string

input:string.in output:string.out
Time Limits: 1000 ms Memory Limits: 262144 KB Detailed Limits

題目描述

給定一個由小寫字母組成的字串 s。有 m 次操作,每次操作給 定 3 個引數 l,r,x。如果 x=1,將 s[l]~s[r]升序排序;如果 x=0,將 s[l]~s[r] 降序排序。你需要求出最終序列。

輸入描述

第一行兩個整數 n,m。第二行一個字串 s。接下來 m 行每行三 個整數 l,r,x。

輸出描述

一行一個字串表示答案。

樣例輸入

5 2
cabcd
1 3 1
3 5 0

樣例輸出

abdcc

題解:

先說我(廢)怎(柴)麼(說)想(廢)的(話)(直接下滑有分割線)
看到第一題就想到區間翻轉,想到區間翻轉就想起昨天看到的splay的區間插入與翻轉,
然而我不會
想到區間就想到每個區間在被轉後就有序了,能不能給區間打標記,合併區間時二分插入?
然而一點也不現實,
先不說怎麼二分插入,合併多個區間時,我只想到一個一個向最大的區間插入
其時間複雜度還不如暴力快排
而且還要分裂合併區間,極其弱小的我只好發呆睡覺出去轉
出去閒逛時,聽到某su對某wu說了一句第一題splay。
於是還真以為splay正解,於是開始想······
__________________________**分割線**_________________________________


然而我還是不會,
但在想二分插入時我便想到了標記升序,逆序,與無序,這是一個思路
能不能用線段樹合併區間?
如果我們給每個節點(代表一個區間)打上標記,再記錄在這個區間中26個字母分別有多少個
不就可以知道其順序了?
然後思路就清晰了。
我們可以先建出一棵線段樹,維護以下每個節點所代表的區間中26個字母分別有多少個
然後就是區間排序了,
我們把l~r這個區間中26個字母分別有多少個算出來,
然後再按要求的順序插入回線段樹中,因為桶排起到了排序的效果,所以按順序插入回去就行了
就這麼簡單?當然不止這些
如果我們每個節點都插入一次就會很自然的時超。
但我們可以打懶惰標記啊,由於我們知道一個區間中26個字母分別有多少個,又知道其順序(升或降),輸出和修改時按這個(隨便搞搞
)來操作不就行了?
可是如果區間互相覆蓋呢?沒關係,標記下傳就行了。

修改區間的具體操作是這樣的:
我們先統計l~r這個區間中26個字母分別有多少個,設gx[1~26]表示26個字母分別有多少個
二分查詢l~r所包含的區間,
遇到有標記的點就用它存下的26個字母個數更新它的左右兒子(順序按標記來),
然後把標記傳給它的左右兒子(它的左右兒子還沒更新時,其標記可能與真正順序不同,但我們可以用其父親的標記覆蓋它),
這樣就可以保證掃到不需查詢的兒子時仍然有序
找到完全包含的區間就把其字母個數加入gx,否則二分查詢。
統計完後分配到l~r中
如果完全包含一個區間則先將其清空,將gx剩下的字母中前(或後)r-l+1個字母塞進去,再打上有序的標記(0表示無序,1和2分別表示降序升序,這樣下次掃到這裡就可以更新其兒子)
否則我們繼續二分查詢

最後輸出很簡單,先左後右深搜,搜到一個有順序標記的區間就按順序輸出
否則還是二分查詢。

由於我程式碼太醜了,所以超了4000bytes。但時間還是(比較優秀)不太好。
大多C++選手不知跑得很慢,不過還是有一部分不開o3o2也很優秀而優美的,而有一些開了o2o3還是700+ms。
作為一個pascal選手500+ms我很驕傲。
這道題個人認為比較好改,畢竟是考場切的,有些地方不理解自己思考一下就好。
居然是新初二唯一一個切掉的,還是考場切掉的11個之一(113人),然而被兩個新初二沒切題拼分踩下去了,oj好卡,差二十分鐘就交不上去了。第一次下夏令營A組18新初二第三
貼一段標

procedure zh(x,l,r,y,z:longint);//統計
var
    mid,vs,mp,o,i:longint;
begin
    if l<>r then
    begin
        mid:=(l+r)div 2;
        if (y<=l)and(z>=r) then for i:=1 to 26 do v[i]:=v[i]+t[x,i]//完全包含則全部加入
        else
        begin
            if bz[x]<>0 then
            begin
                if bz[x]=1 then vs:=26
                else vs:=1;//頭指標
                bz[son[x,1]]:=bz[x];
                bz[son[x,2]]:=bz[x];
                t[son[x,1]]:=qk;
                t[son[x,2]]:=qk;
                cs:=t[x];
                mp:=mid-l+1;
                o:=1;
                while mp>0 do//下傳
                begin
                    while cs[vs]=0 do
                    begin
                        if bz[x]=2 then inc(vs)
                        else dec(vs);
                    end;
                    if cs[vs]>=mp then
                    begin
                        cs[vs]:=cs[vs]-mp;
                        t[son[x,o],vs]:=mp;
                        mp:=0;
                        if o=1 then//塞完左區間塞右區間
                        begin
                            o:=2;
                            mp:=r-mid;
                        end
                        else break;
                    end
                    else
                    begin
                        mp:=mp-cs[vs];
                        t[son[x,o],vs]:=cs[vs];
                        cs[vs]:=0;
                    end;
                end;
                bz[x]:=0;
            end;
            if (y<=mid)and(z>=mid+1) then//二分查詢
            begin
                zh(son[x,1],l,mid,y,z);
                zh(son[x,2],mid+1,r,y,z);
            end
            else
            begin
                if (z<=mid)then zh(son[x,1],l,mid,y,z)
                else zh(son[x,2],mid+1,r,y,z);
            end;
        end;
    end
    else for i:=1 to 26 do v[i]:=v[i]+t[x,i];
end;
procedure fp(x,l,r,y,z,bs:longint);//修改
var
    mid,mp,i:longint;
begin
    if l<>r then
    begin
        mid:=(l+r)div 2;
        if (y<=l)and(z>=r) then
        begin
            bz[x]:=bs;
            t[x]:=qk;
            mp:=r-l+1;
            while mp<>0 do//塞滿整個區間
            begin
                while v[kt]=0 do//更新頭指標,初始值按升序降序來定
                begin
                    if bs=2 then inc(kt)
                    else dec(kt);
                end;
                if v[kt]>mp then
                begin
                    v[kt]:=v[kt]-mp;
                    t[x,kt]:=mp;
                    mp:=0;
                end
                else
                begin
                    mp:=mp-v[kt];
                    t[x,kt]:=v[kt];
                    v[kt]:=0;
                end;
            end;
        end
        else
        begin//二分查詢
            if (y<=mid)and(z>=mid+1) then
            begin
                fp(son[x,1],l,mid,y,z,bs);
                fp(son[x,2],mid+1,r,y,z,bs);
            end
            else
            begin
                if (z<=mid)then fp(son[x,1],l,mid,y,z,bs)
                else fp(son[x,2],mid+1,r,y,z,bs);
            end;
            for i:=1 to 26 do t[x,i]:=t[son[x,1],i]+t[son[x,2],i];
        end;
    end
    else
    begin
        t[x]:=qk;
        while v[kt]=0 do
        begin
            if bs=2 then inc(kt)
            else dec(kt);
        end;
        v[kt]:=v[kt]-1;
        t[x,kt]:=1;
    end;
end;