時間限制: 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外的所有其他節點。為此引入...