問題描述
給你乙個長度為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 6
2<=n<=100000**1<=m<=100000
原序列1<=ai<=1000
每次1<=k<=n,1<=l<=r<=n,1<=d<=1000
感謝nodgd命題並提供資料splay裸題,主要是留個紀念。
首先按照編號建立平衡樹,具體方法是加兩個虛擬節點1,n+2,再將原數列中的數按key值為編號+1插入平衡樹。
對於區間操作的整體思想是:提取乙個區間[l,r],就把key為(l+1)-1的節點旋轉到根,再把key為(r+1)+1的節點旋轉到根的右兒子。此時這個節點的左子樹就正好是需要提取的區間。這個由二叉檢索樹的性質是正確的。
於是,要得到區間和、區間極值,只需要維護以某個節點為根的子樹的和、子樹中的權值最大值即可。這些容易在旋轉的同時更新。
修改某個點的權值,我採用的是先將該點旋轉到根,再更新根節點的max,sum,val值。也可以在查詢該點的同時更新路徑上所有點的max,sum值。
最後是區間翻轉問題。提取區間後,只需要打上lazy標記,訪問到的時候下放,交換左右兩棵子樹即可。雖然splay是自下往上的過程,但是splay前一定要先找到需要splay到根的點。這個過程是自上往下的,此時下放即可,不會造成操作的衝突。
注意lazy與線段樹里略有不同:線段樹中打上lazy標記的點一定是已經處理完該點的操作了,而本題中是下放時才進行操作。所以打lazy標記時應當用lazy^=1而不是lazy=1。
**:
#include#include#define maxn 100005
using namespace std;
int tmax(int x,int y,int z)
int n;
int rt,tot,fa[maxn],ls[maxn],rs[maxn],pri[maxn],val[maxn],lazy[maxn],sum[maxn],max[maxn],size[maxn];
void update(int x,int y)
void putdown(int p)
void zig(int x)
fa[x]=z;fa[y]=x;fa[rs[x]]=y;
ls[y]=rs[x];rs[x]=y;
update(x,y);
}void zag(int x)
fa[x]=z;fa[y]=x;fa[ls[x]]=y;
rs[y]=ls[x];ls[x]=y;
update(x,y);
}void splay(int x,int t)
else
else}}
if(!t)rt=x;
}void ins(int k,int v)
p=ls[p];
}else
p=rs[p];}}
size[tot]=1;fa[tot]=p;pri[tot]=k;val[tot]=max[tot]=sum[tot]=v;
splay(tot,0);
}int getkth(int k)
}void add(int k,int d)
void prepare(int x,int y)
int getsum(int x,int y)
int getmax(int x,int y)
void rev(int x,int y)
int main()
while(m--)
else
if(op==2)
else
if(op==3)
else
if(op==4)
else
}}
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行每行輸入兩個數 對應操作的區間 輸出最後翻轉完成後的序列 ...
平衡樹 Splay 區間翻轉 模板
luogup3391一道模板題 學習了spl ay splay spla y區間翻轉的姿勢 具體就是先建兩個虛擬節點1,n 2 1,n 2 1,n 2,然後按節點下標 1 1 1將區間樹建出來,這時候排名為k kk的就是第k kk個數。翻轉的時候先把 l 1 1 l 1 1 l 1 1提到根,再把 ...
區間翻轉問題
給你乙個長度為n的序列和m個操作 1.查詢第k個數的值 2.將第k個數增加d 3.查詢一段區間的和 4.查詢一段區間的最大值 5.將一段區間鏡面翻轉 例如序列,將從2到5的區間翻轉後得到序列 對於除操作2,5以外的操作,輸出相應的答案 第一行兩個正整數n,m 第二行n個整數,為初始的序列 第三行到底...