洛谷题单 【数据结构2-1】二叉堆与树状数组
洛谷题单 【数据结构2-1】二叉堆与树状数组
P1878 舞蹈课 优先队列+模拟
每次要取出最小值,考虑用优先队列维护。维护出跳舞的两个人的
然后每次取出队头元素,判断左右两边的是否可以构成新的舞伴加入优先队列即可。
注意:每个人只能和一个人组成舞伴,所以要标记一下。以及对于
#include<bits/stdc++.h>
using namespace std;
using i64=long long;
struct node{
int l,r;
int val;
bool operator<(const node &u)const{
return (val==u.val?l>u.l:val>u.val);
}
};
void Showball(){
int n;
cin>>n;
string s;
cin>>s;
s="?"+s;
vector<int> a(n+1),pre(n+2),suf(n+2);
for(int i=1;i<=n;i++){
cin>>a[i];
pre[i]=i-1;
suf[i]=i+1;
}
priority_queue<node> pq;
for(int i=1;i<n;i++){
if(s[i]!=s[i+1]) pq.push({i,i+1,abs(a[i]-a[i+1])});
}
vector<array<int,2>> ans;
vector<int> st(n+1);
while(pq.size()){
node u;
while(1){
u=pq.top();
pq.pop();
if(pq.empty()||!st[u.l]&&!st[u.r]) break;
}
if(st[u.l]==1||st[u.r]==1) continue;
ans.push_back({u.l,u.r});
st[u.l]=st[u.r]=1;
int l=pre[u.l],r=suf[u.r];
pre[r]=l;suf[l]=r;
if(l>=1&&r<=n&&s[l]!=s[r]) pq.push({l,r,abs(a[l]-a[r])});
}
cout<<ans.size()<<"\n";
for(auto [l,r]:ans) cout<<l<<" "<<r<<"\n";
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t=1;
//cin>>t;
while(t--){
Showball();
}
return 0;
}
对顶堆
P1168 中位数 对顶堆
用对顶堆维护好单调序列,并且维护两个堆数量均衡,那么最后元素多一个的堆顶就是中位数。
#include<bits/stdc++.h>
using namespace std;
using i64=long long;
void Showball(){
int n;
cin>>n;
priority_queue<int,vector<int>,greater<int>> minq;
priority_queue<int> maxq;
int s1=0,s2=0;
for(int i=1;i<=n;i++){
int x;
cin>>x;
if(i==1) maxq.push(x),s1++;
else{
int v=maxq.top();
if(x>=v) minq.push(x),s2++;
else maxq.push(x),s1++;
}
if(s1-s2==2){
minq.push(maxq.top());
maxq.pop();
s1--;s2++;
}
if(s2-s1==2){
maxq.push(minq.top());
minq.pop();
s1++;s2--;
}
if(i&1){
if(s1>s2) cout<<maxq.top()<<"\n";
else cout<<minq.top()<<"\n";
}
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t=1;
//cin>>t;
while(t--){
Showball();
}
return 0;
}
P2168 [NOI2015] 荷马史诗 堆+哈夫曼树
模仿 合并果子 的方式,每
#include<bits/stdc++.h>
using namespace std;
using i64=long long;
struct node{
i64 w,h;
bool operator<(const node &u)const{
return (w==u.w?h>u.h:w>u.w);
}
};
void Showball(){
int n,k;
cin>>n>>k;
priority_queue<node> pq;
for(int i=1;i<=n;i++){
i64 x;
cin>>x;
pq.push({x,1});
}
int cnt=(k-1-(n-1)%(k-1))%(k-1);
for(int i=0;i<cnt;i++) pq.push({0,1});
cnt+=n;
i64 ans=0;
while(cnt>1){
i64 tmp=0,maxh=0;
for(int i=0;i<k;i++){
tmp+=pq.top().w;
maxh=max(maxh,pq.top().h);
pq.pop();
}
ans+=tmp;
pq.push({tmp,maxh+1});
cnt-=k-1;
}
cout<<ans<<"\n"<<pq.top().h-1;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t=1;
//cin>>t;
while(t--){
Showball();
}
return 0;
}
P2161 [SHOI2009] 会场预约 set/线段树染色
set
可以用之前的经典Trick,通过重载运算符,利用 set
的 find
函数快速找到相交区间。
然后暴力统计即可。代码十分好写。
#include<bits/stdc++.h>
using namespace std;
using i64=long long;
struct node{
int l,r;
bool operator<(const node &u)const{
return r<u.l;
}
};
void Showball(){
int n;
cin>>n;
set<node> st;
while(n--){
char op;
cin>>op;
if(op=='A'){
int l,r;
cin>>l>>r;
auto it=st.find({l,r});
int cnt=0;
while(it!=st.end()){
cnt++;
st.erase(it);
it=st.find({l,r});
}
st.insert({l,r});
cout<<cnt<<"\n";
}else{
cout<<st.size()<<"\n";
}
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t=1;
//cin>>t;
while(t--){
Showball();
}
return 0;
}
线段树染色
对于
对于
懒标记:0表示未染色,-1表示区间多种颜色,其余值表示颜色值。
#include<bits/stdc++.h>
using namespace std;
using i64=long long;
const int N=2e5+10;
int ans,cnt;
int st[N];
//线段树 染色
struct node{
int l,r;
int color;
int tag;//0 无颜色,-1 多种颜色
}tr[N*4];
#define ls u<<1
#define rs u<<1|1
void pushup(node &u,node &l,node &r){
if(l.color==r.color) u.color=l.color;
else u.color=-1;
}
void pushup(int u){
pushup(tr[u],tr[ls],tr[rs]);
}
void addtag(node &u,int tag){
if(!tag) return;
u.color=tag;
u.tag=tag;
}
void pushdown(int u){
addtag(tr[ls],tr[u].tag);
addtag(tr[rs],tr[u].tag);
tr[u].tag=0;
}
void build(int u,int l,int r){
tr[u].l=l,tr[u].r=r;
tr[u].tag=0;tr[u].color=0;
if(l==r) return;
int mid=l+r>>1;
build(ls,l,mid),build(rs,mid+1,r);
pushup(u);
}
void modify(int u,int l,int r,int tag){//区间修改
if(l<=tr[u].l&&tr[u].r<=r) {
addtag(tr[u],tag);
return;
}
int mid=tr[u].l+tr[u].r>>1;
pushdown(u);
if(l<=mid) modify(ls,l,r,tag);
if(r>mid) modify(rs,l,r,tag);
pushup(u);
}
void query(int u,int l,int r){//区间查询
if(l<=tr[u].l&&tr[u].r<=r){
if(!tr[u].color) return;
if(tr[u].color<0){
pushdown(u);
int mid=tr[u].l+tr[u].r>>1;
if(l<=mid) query(ls,l,r);
if(r>mid) query(rs,l,r);
}else{
if(!st[tr[u].color]){
ans--;
st[tr[u].color]=1;
cnt++;
}
}
return;
}
pushdown(u);
int mid=tr[u].l+tr[u].r>>1;
if(l<=mid) query(ls,l,r);
if(r>mid) query(rs,l,r);
}
void Showball(){
int n;
cin>>n;
build(1,1,200000);
for(int i=1;i<=n;i++){
char op;
cin>>op;
if(op=='A'){
int l,r;
cin>>l>>r;
query(1,l,r);
cout<<cnt<<"\n";
cnt=0;
modify(1,l,r,i);
ans++;
}else{
cout<<ans<<"\n";
}
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t=1;
//cin>>t;
while(t--){
Showball();
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】