NOI2004 鬱悶的出納員

2022-05-09 11:51:14 字數 1711 閱讀 3196

嘟嘟嘟

\(splay\)我又來了

1.插入結點:正常操作,不說了。

1.全域性加減:單開乙個變數表示變化量即可,不用區間修改打\(lazy\)標記。

2.刪除小於\(x\)的數:找\(x\)的後繼(包括自己),然後把\(x\)旋到根,刪除左子樹即可。

3.查詢第\(k\)大的數:如果\(k\)小於右子樹大小,到右子樹去找;否則如果\(k\)小於右子樹大小加上當前節點大小\(size\),直接返回當前節點權值;否則\(k -= size\),去左子樹找。

主要思路就是這些。

細節:1.別忘了先往樹里新增\(-inf\)和\(inf\),防止出現找不到前驅或者後繼的情況。

2.由於第一條,所以每次刪除後要再新增\(-inf\),查詢的時候應該查第\(k + 1\)大的元素。

然後因為我剛開始學,所以因為各種小毛病調了好久……

#include#include#include#include#include#include#include#include#include#includeusing namespace std;

#define enter puts("")

#define space putchar(' ')

#define mem(a, x) memset(a, x, sizeof(a))

#define rg register

typedef long long ll;

typedef double db;

const int inf = 0x3f3f3f3f;

const db eps = 1e-8;

const int maxn = 1e6 + 5;

inline ll read()

inline void write(ll x)

int n, min, delta = 0, sum = 0;

char c[2];

struct tree

t[maxn];

int root, ncnt = 0;

void _printtree(int now) //除錯用

void _sizck(int now)

void pushup(int now)

void rotate(int x)

void splay(int x, int s)

rotate(x);

}if(!s) root = x;

}void insert(int x)

int now = root, f = 0;

while(now && t[now].val != x) f = now, now = t[now].ch[x > t[now].val];

if(now) t[now].cnt++;

else

splay(now, 0);

}void find(int x)

int nxt(int x)

void clear(int& now)

int del(int x) //nxt(x) go to root, and del left son

//the num >= x!

int query(int k)

}int main()

//_printtree(root);

}write(sum), enter;

return 0;

}

noi 2004 鬱悶的出納員

原題位址 花了一兩天真正的熟悉了treap,對於乙個東西,本蒟蒻認為,不應該要會,還應會熟練的寫,像哈狗寫這個只需十分鐘 好吧,話歸正題 先推薦另類解法 戳進去 此題解法很多bit 權值線段樹 各種平衡樹 準備抽空寫 是一道很棒的模板題。這道題我們把每次全體加的工資和減的弄到乙個變數,姑且叫為w,把...

NOI2004 鬱悶的出納員

大致題意就是對初始為空的數列的各種操作233 題解 splay啦 其中可能會遇到的幾個問題 1.如何刪去低於min的點 找到數列中min的後繼提為根,把根的左孩子丟 shan 了就完成了 很容易yy到的對吧 2.如何處理對當前數列中的數進行 k 開個全域性變數存整體的波動 值ff。那麼刪點的時候就把...

NOI2004 鬱悶的出納員

點此看題 這道題很新的一點就是加工資和減工資,這貌似要用到區間修改。但是細細想想,操作的物件是全樹,我們可以維護乙個累積的修改值,新加入乙個點的話要刪去之前的累計的修改值,對於減工資的情況,判斷有沒有低於最低的限制。注意如果乙個一來人就低於最低線,那麼這個人不被統計在最後的刪除人數中。include...