區間翻轉問題

2021-08-17 19:06:21 字數 1725 閱讀 8394

給你乙個長度為n的序列和m個操作

1.查詢第k個數的值

2.將第k個數增加d

3.查詢一段區間的和

4.查詢一段區間的最大值

5.將一段區間鏡面翻轉(例如序列,將從2到5的區間翻轉後得到序列)

對於除操作2,5以外的操作,輸出相應的答案

第一行兩個正整數n,m

第二行n個整數,為初始的序列

第三行到底m+2行,每行若干個整數

·如果第乙個數為1,那麼後面乙個正整數k,表示查詢第k個數的值

·如果第乙個數是2,那麼後面兩個正整數k,d,表示將ak增加d

·如果第乙個數為3,那麼後面兩個正整數l,r,表示查詢從al到ar的區間和

·如果第乙個數為4,那麼後面兩個正整數l,r,表示查詢從al到ar的最大值

·如果第乙個數為5,那麼後面兩個正整數l,r,表示翻轉從al到ar的這個區間

除操作2,5外每個操作輸出佔一行,乙個整數,為本次提問的答案

6 8

1 2 3 4 5 6

1 4

3 2 5

4 2 2

5 2 5

3 1 3

5 2 5

2 5 1

4 1 6

4 14

2 10

62<=n<=100000

1<=m<=100000

原序列1<=ai<=1000

每次1<=k<=n,1<=l<=r<=n,1<=d<=1000

我們維護一棵平衡樹,鍵值為各點的編號。乙個點的左子樹的實際位置在這個點之前,右子樹的實際位置在這個點之後。初始時任一點的左子樹(如果有的話)編號全部小於該點編號,右子樹編號全部大於該點編號。並記錄好每個點為根的樹的最大元素、元素和。

一號操作,我們只用類似於平衡樹「查詢第k小」的方法就可以了。

二號,先將這個點找到(見一號操作),再旋到根。這樣,修改操作就只會對根節點有影響了。

三號,找到第(l-1)個數的編號,旋到根。再找到第(r+1)個數,旋到根的右兒子。輸出(r+1)個數的左兒子的元素和就行了(解釋略)。

四號同三號。

五號,略同三號,在(r+1)個數的左兒子打乙個lazy標記,以後討論到帶標記的點就交換左右兒子並下放標記。由於偶數個標記不影響結果,建議使用異或修改標記。

用的splay

#include #include #include using namespace std;

const int q=100005;

int si[q],ls[q],rs[q],f[q],v[q],maxn[q],sum[q],root=1,n,ch[q]=;

void lx(int x)

void rx(int x)

void pd(int x)

void splay(int x,int

goal)

else

}if(f[x]==0)root=x;

}int gk(int k)

return p;

}int main()

else

if(ls[x])x=ls[x];

else

}f[i]=x;

splay(i,0);

}while(m--)

if(i==3||i==4)

if(i==5)

}return

0;}

區間翻轉問題 Splay

問題描述 給你乙個長度為n的序列和m個操作 1.查詢第k個數的值 2.將第k個數增加d 3.查詢一段區間的和 4.查詢一段區間的最大值 5.將一段區間鏡面翻轉 例如序列,將從2到5的區間翻轉後得到序列 對於除操作2,5以外的操作,輸出相應的答案 輸入格式 第一行兩個正整數n,m 第二行n個整數,為初...

Splay之區間翻轉問題

給你 n 個數 分別為 1,2,3,4 n 然後有 m 個操作,每個操作對應一段區間,將區間的數進行翻轉。比如 1,2,3,4,5 這段序列 操作區間為 2 4 翻轉完成後的序列為 1,4,3,2,5 第一行分別輸入 n,m 第2行到m 1行每行輸入兩個數 對應操作的區間 輸出最後翻轉完成後的序列 ...

4975 區間翻轉

小q和tangjz正在乙個長度為n的序列a 1,a 2,a n上玩乙個有趣的關於區間翻轉的遊戲。小q和tangjz輪流行動 小q先手。每次行動方玩家需要選擇乙個長度為4x 2或4x 3的區間 l,r 1 l r n 其中x是該玩家自行選擇 的非負整數,然後將a l,a a a r翻轉,例如1 3 2...