題目鏈結
這道題需要動態插入,刪除,求排名,看到這就想到了平衡樹。由於本人只會splay,所以就用splay來做這道題,這道題插入和刪除都是模板,但是題中還有乙個比價坑的地方就是工資的調整。但我做不到在平衡樹上修改點權。如果每乙個都去插入和刪除的複雜度顯然非常高。看了題解發現,可以維護乙個變數來記錄每次工資調整時的值delta,像這樣的話我們插入的k值就應該是k-delta,為什麼要這樣做呢,因為我們顯然無法修改之前的點權,這樣一來就是維護乙個相對的大小。
重點還有如何把工資低於下界的人都刪去。我們在操作之前提前插入兩個哨兵節點+/-inf,這樣可以避免操作時的錯誤,這是乙個技巧,需要記住。在刪除的時候把權值為-inf的點旋轉到根節點,然後將全值為下界的點轉到根節點的右兒子上,這是根節點右兒子的左兒子就是比工資下界小的所有節點,然後直接刪除即可。
注意再求排名的時候要減去兩個插入的哨兵節點。
**如下:
#includeusingview codenamespace
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;
}
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表示此時對整棵樹的改變值,這樣一來,在每次插入節點...