P1486 NOI2004 鬱悶的出納員

2022-03-17 23:21:21 字數 2094 閱讀 7957

題目鏈結

這道題需要動態插入,刪除,求排名,看到這就想到了平衡樹。由於本人只會splay,所以就用splay來做這道題,這道題插入和刪除都是模板,但是題中還有乙個比價坑的地方就是工資的調整。但我做不到在平衡樹上修改點權。如果每乙個都去插入和刪除的複雜度顯然非常高。看了題解發現,可以維護乙個變數來記錄每次工資調整時的值delta,像這樣的話我們插入的k值就應該是k-delta,為什麼要這樣做呢,因為我們顯然無法修改之前的點權,這樣一來就是維護乙個相對的大小。

重點還有如何把工資低於下界的人都刪去。我們在操作之前提前插入兩個哨兵節點+/-inf,這樣可以避免操作時的錯誤,這是乙個技巧,需要記住。在刪除的時候把權值為-inf的點旋轉到根節點,然後將全值為下界的點轉到根節點的右兒子上,這是根節點右兒子的左兒子就是比工資下界小的所有節點,然後直接刪除即可。

注意再求排名的時候要減去兩個插入的哨兵節點。

**如下:

#includeusing

namespace

std;

const

int maxn=1e6+7

;const

int inf=0x7fffffff

;int

n,minn;

char

opt[maxn];

int key[maxn],fa[maxn],cnt[maxn],size[maxn],ch[maxn][2

];int

rt,sz;

intk;

inttot;

intdelta;

void pushup(int

x)bool check(int

x)void clear(int

x)void rotate(int

x)void splay(int x,int

goal)

if(!goal) rt=x;

}void insert(int

x)

int now=rt,f=0

;

while(1

) f=now,now=ch[now][key[now]

if(!now)

}}int

nxt()

intpre()

int id(int

x) }

}int rank(int

x) ans+=cnt[now];

now=ch[now][1

]; }

}}void del(int

x)

if(!ch[rt][1]&&!ch[rt][0

])

if(!ch[rt][1

])

else

if(!ch[rt][0

])

int oldroot=rt,left=pre();

splay(left,0);

fa[ch[oldroot][

1]]=rt;

ch[rt][

1]=ch[oldroot][1

]; clear(oldroot);

pushup(rt);

}int val(int

x) }

}int

main()

if(opt[0]=='a'

)

if(opt[0]=='s'

)

if(opt[0]=='f'

)

int ans=val(kkksc03+2-k);

printf(

"%d\n

",ans+delta);}}

int kkksc03=rank(inf)-2

;

int ans=tot-kkksc03;

printf(

"%d\n

",ans);

return0;

}

view code

P1486 NOI2004 鬱悶的出納員

平衡樹的題目 題目中的全部減少可以通過維護全域性的減少量s 不過我使用了打tag的方式 然後每次插入的時候插入 v i s 刪除的時候直接在平衡樹上二分移除對應的子樹即可 include include include include using namespace std int nodecnt ...

NOI2004, 洛谷P1486 鬱悶的出納員

題目描述 oier公司是一家大型專業化軟體公司,有著數以萬計的員工。作為一名出納員,我的任務之一便是統計每位員工的工資。這本來是乙份不錯的工作,但是令人鬱悶的是,我們的老闆反覆無常,經常調整員工的工資。如果他心情好,就可能把每位員工的工資加上乙個相同的量。反之,如果心情不好,就可能把他們的工資扣除乙...

bzoj1503 NOI2004 鬱悶的出納員

本題依然是一道資料結構題,對本題而言,依然可以用splay來解。本題的乙個難點 對於我這個弱菜而言 是如何動態的改變平衡樹中的值。其實我們可以借鑑線段樹中的lazy tag的思想,因為若要變動則是整棵樹一起變,所以我們可以開設乙個全域性變數delta表示此時對整棵樹的改變值,這樣一來,在每次插入節點...