codevs 3243 區間反轉(線段樹)

2021-07-22 12:45:53 字數 2113 閱讀 6899

時間限制: 1 s

空間限制: 256000 kb

題目等級 : 鑽石 diamond

題解

檢視執行結果

給出n個數,要求做m次區間翻轉(如1 2 3 4變成4 3 2 1),求出最後的序列

輸入描述 input description

第一行乙個數n,下一行n個數表示原始序列,在下一行乙個數m表示m次翻轉,之後的m行每行兩個數l,r表示將區間[l,r]翻轉。

輸出描述 output description

一行n個數 , 表示最終序列。

樣例輸入 sample input

4

1 2 3 4

2

1 2

3 4

樣例輸出 sample output

2 1 4 3

資料範圍及提示 data size & hint

對於30%的資料滿足n<=100 , m <= 10000

對於100%的資料滿足n <= 150000 , m <= 150000

對於100%的資料滿足n為2的冪,且l = i * 2^j + 1 , r = (i + 1) * 2^j

【題解】【線段樹】

【這其實,是道水題。用線段樹維護區間更改。線段樹的葉子節點存每個位置是原序列中的第幾號元素。

然後維護當前點的編號和每個點的左右兒子的序號,反轉區間時,

交換左右兒子即可,不過要注意,

每次打標記的時候,不能直接把delta置1(防止覆蓋原標記),用異或取反

(注意,這樣做是有bug的,只有在交換區間正好是線段樹中的整區間才行。

原題中有這個限制,所以可以這樣做)】

#include#include#includeusing namespace std;

int tree[6000010][3],delta[6000010];

int n,m,a[150010],num[150010];

inline void swap(int now)

inline void updata(int now)

inline void pushdown(int now)

}void build(int now,int l,int r)

int mid=(l+r)>>1;

build((now<<1),l,mid);

build((now<<1)|1,mid+1,r);

updata(now);

}void change(int now,int l,int r,int al,int ar)

int mid=(l+r)>>1;

pushdown(now);

if(al<=mid) change(tree[now][1],l,mid,al,ar);

if(ar>mid) change(tree[now][2],mid+1,r,al,ar);

}int ask(int now,int l,int r,int al,int ar)

int main()

for(j=1;j<=n;++j) num[j]=ask(1,1,n,j,j);

for(j=1;j<=n;++j) printf("%d ",a[num[j]]);

return 0;

}

3243 區間翻轉

時間限制 1 s 空間限制 256000 kb 題目等級 鑽石 diamond 題解給出n個數,要求做m次區間翻轉 如1 2 3 4變成4 3 2 1 求出最後的序列 輸入描述 input description 第一行乙個數n,下一行n個數表示原始序列,在下一行乙個數m表示m次翻轉,之後的m行每行...

線段樹(2)區間修改

快速序列操作i,給出乙個n個元素的陣列a1,a2,an,你的任務是設計乙個資料結構支援一下兩種操作 set l,r,v 把al,al 1,ar的值全部修改為v v 0 query l,r 計算子串行al,al 1,ar的元素和 最小值和最大值。include include using namesp...

線段樹2(區間更新)

區間更新是指更新某個區間內的葉子節點的值,因為涉及到的葉子節點不止乙個,而葉子節點會影響其相應的非葉父節點,那麼回溯需要更新的非葉子節點也會有很多,如果一次性更新完,操作的時間複雜度肯定不是o lgn 例如當我們要更新區間 0,3 內的葉子節點時,需要更新出了葉子節點3,9外的所有其他節點。為此引入...