国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

BZOJ 1251: 序列終結者 Splay

2019-11-08 02:04:00
字體:
來源:轉載
供稿:網友

Description

網上有許多題,就是給定一個序列,要你支持幾種操作:A、B、C、D。一看另一道題,又是一個序列 要支持幾種操作:D、C、B、A。尤其是我們這里的某人,出模擬試題,居然還出了一道這樣的,真是沒技術含量……這樣 我也出一道題,我出這一道的目的是為了讓大家以后做這種題目有一個“庫”可以依靠,沒有什么其他的意思。這道題目 就叫序列終結者吧。 【問題描述】 給定一個長度為N的序列,每個序列的元素是一個整數(廢話)。要支持以下三種操作: 1. 將[L,R]這個區間內的所有數加上V。 2. 將[L,R]這個區間翻轉,比如1 2 3 4變成4 3 2 1。 3. 求[L,R]這個區間中的最大值。 最開始所有元素都是0。 Input

第一行兩個整數N,M。M為操作個數。 以下M行,每行最多四個整數,依次為K,L,R,V。K表示是第幾種操作,如果不是第1種操作則K后面只有兩個數。 Output

對于每個第3種操作,給出正確的回答。 Sample Input 4 4

1 1 3 2

1 2 4 -1

2 1 3

3 2 4

Sample Output 2

【數據范圍】

N<=50000,M<=100000。

Splay裸題。

//bzoj 1251 splay 復習//支持操作為//1: 區間+//2: 區間翻轉//3: 區間求最大#include <bits/stdc++.h>using namespace std;const int maxn = 50010;const int maxm = 100010;namespace SplayTree{ int siz[maxn], fa[maxn], ma[maxn], rev[maxn], lazy[maxn], val[maxn]; //siz代表節點的sz,fa代表父親節點,ma代表最大值,rev翻轉標記 //lazy 區間+, val 值 int ch[maxn][2], tot, root; //tot代表開新節點的時間戳,root代表splay的樹根,ch[i][2],i的左右兒子 void newnode(int &rt, int father, int k){ rt = ++tot; siz[rt] = 1, fa[rt] = father; ma[rt] = val[rt] = k; rev[rt] = lazy[rt] = ch[rt][0] = ch[rt][1] = 0; } void pushup(int rt){ //pushup 從底向上更新 siz[rt] = 1, ma[rt] = val[rt]; if(ch[rt][0] != 0) siz[rt] += siz[ch[rt][0]], ma[rt] = max(ma[rt], ma[ch[rt][0]]); if(ch[rt][1] != 0) siz[rt] += siz[ch[rt][1]], ma[rt] = max(ma[rt], ma[ch[rt][1]]); } void pushdown(int rt){ //pushdown 從上向下更新 if(!rt) return; if(lazy[rt]){ //區間+懶惰標記傳遞 int l = ch[rt][0], r = ch[rt][1]; if(l != 0) ma[l] += lazy[rt], val[l] += lazy[rt], lazy[l] += lazy[rt]; if(r != 0) ma[r] += lazy[rt], val[r] += lazy[rt], lazy[r] += lazy[rt]; lazy[rt] = 0; } if(rev[rt]){ //區間翻轉懶惰標記傳遞 int l = ch[rt][0], r = ch[rt][1]; if(l != 0) rev[l] ^= 1, swap(ch[l][0], ch[l][1]); if(r != 0) rev[r] ^= 1, swap(ch[r][0], ch[r][1]); rev[rt] ^= 1; } } void rotate(int x){ //旋轉,把x轉到根節點,kind為1代表右旋,kind為0代表左旋 int y = fa[x], kind = ch[y][1] == x; pushdown(y), pushdown(x); ch[y][kind] = ch[x][!kind]; fa[ch[y][kind]] = y; ch[x][!kind] = y; fa[x] = fa[y]; fa[y] = x; ch[fa[x]][ch[fa[x]][1] == y] = x; pushup(y), pushup(x); } void splay(int x, int goal) //伸展操作,把根為r的子樹調整為goal { while(fa[x] != goal) { int y = fa[x], z = fa[y]; if(z == goal) rotate(x); else if((ch[y][1] == x) == (ch[z][1] == y)) rotate(y), rotate(x); else rotate(x), rotate(x); } if(goal == 0) root = x; } void build(int &rt, int l, int r, int father){ //建立一顆空的splaytree if(l > r) return; int mid = (l + r) / 2; newnode(rt, father, 0); //遞歸申請新節點 build(ch[rt][0], l, mid - 1, rt); build(ch[rt][1], mid + 1, r, rt); pushup(rt); } int find(int x, int k){ //查找第k位置在splaytree中的位置 pushdown(x); int lsum = siz[ch[x][0]] + 1; if(lsum == k) return x; else if(lsum < k) return find(ch[x][1], k - lsum); else return find(ch[x][0], k); } void update_val(int l, int r, int v){ //區間更新+ splay(find(root, l), 0); splay(find(root, r + 2), root); lazy[ch[ch[root][1]][0]] += v; ma[ch[ch[root][1]][0]] += v; val[ch[ch[root][1]][0]] += v; } void update_rev(int l, int r){ splay(find(root, l), 0); splay(find(root, r + 2), root); int tmp = ch[ch[root][1]][0]; //現在以tmp為根的splaytree就是l,r區間 rev[tmp] ^= 1; swap(ch[tmp][0], ch[tmp][1]); } int querymax(int l, int r){ //查詢區間最大值 splay(find(root, l), 0); splay(find(root, r + 2), root); return ma[ch[ch[root][1]][0]]; }}using namespace SplayTree;int main(){ int n, m; scanf("%d%d", &n, &m); newnode(root, 0, -1); newnode(ch[root][1], root, -1); build(ch[ch[root][1]][0], 1, n, ch[root][1]); for(int i = 1; i <= m; i++){ int cmd, a, b, c; scanf("%d", &cmd); if(cmd == 1){ scanf("%d%d%d", &a, &b, &c); update_val(a, b, c); }else if(cmd == 2){ scanf("%d%d", &a, &b); update_rev(a, b); }else{ scanf("%d%d", &a, &b);
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 临夏市| 通山县| 南部县| 白河县| 天镇县| 瓦房店市| 木里| 芦溪县| 金阳县| 明光市| 额尔古纳市| 沿河| 宣武区| 连江县| 息烽县| 辽源市| 曲靖市| 通榆县| 青阳县| 黎川县| 聂荣县| 北安市| 绩溪县| 灵山县| 乌审旗| 永安市| 保定市| 翁牛特旗| 吉水县| 怀柔区| 洪湖市| 博乐市| 施秉县| 海兴县| 乐都县| 枞阳县| 横山县| 蒙自县| 普安县| 南漳县| 甘泉县|