洛谷P4971:断罪者(左偏树)

解析

看起来就是左偏树的基本操作啊…
然而就是调不过去
吐了qwq

参考了望月大神的实现
感觉清晰的多
就定义并查集维护的是每个点所在的堆的根节点
一下子少了很多恶心的套娃

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define il inline
const int N=4e6+100;
const double eps=1e-9;
inline ll read(){
  ll x=0,f=1;char c=getchar();
  while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
  while(isdigit(c)){x=x*10+c-'0';c=getchar();}
  return x*f;
}
int n,m,w;
ll k;
int ls[N],rs[N],dis[N],tot,f[N],rt[N];
ll val[N];

int bel[N],vis[N];
int find(int x){return x==bel[x]?x:bel[x]=find(bel[x]);}

inline int New(ll v){
  ++tot;ls[tot]=rs[tot]=0;f[tot]=0;dis[tot]=0;
  val[tot]=v;
  return tot;
}
inline void pushup(int x){
  if(dis[rs[x]]>dis[ls[x]]) swap(ls[x],rs[x]);
  dis[x]=dis[rs[x]]+1;
  return;
}
int merge(int u,int v){
  if(!u||!v){
    return u|v;
  }
  if(val[u]<val[v]||(val[u]==val[v]&&u>v)) swap(u,v);
  rs[u]=merge(rs[u],v);
  pushup(u);
  bel[ls[u]]=bel[rs[u]]=bel[u]=u;
  return u;
}

void del(int x){
  if(vis[x]) return;
  vis[x]=1;val[x]=0;
  int o=merge(ls[x],rs[x]);ls[x]=rs[x]=0;
  merge(find(x),o);
  return;
}
void Merge(int u,int v){
  u=find(u),v=find(v);
  if(u==v) return;
  merge(u,v);
  return;
}
void jianshao(int x,int w){
  x=find(x);
  if(val[x]<=w){
    del(x);return;
  }
  int o=x,oo=merge(ls[x],rs[x]);
  ls[o]=rs[o]=0;
  val[o]-=w;ls[o]=rs[o]=0;
  merge(o,oo);
  return;
}


int main(){
  #ifndef ONLINE_JUDGE
  freopen("a.in","r",stdin);
  freopen("a.out","w",stdout);
  #endif
  dis[0]=-1;
  int T=read();w=read();k=read();
  while(T--){
    tot=0;memset(vis,0,sizeof(vis));
    n=read();m=read();
    for(int i=1;i<=n;i++){
      New(read());bel[i]=i;
    }
    for(int i=1;i<=m;i++){
      int op=read();
      if(op==2) del(read());
      else if(op==3){
	int a=read(),b=read();
	jianshao(a,b);
      }
      else{
	Merge(read(),read());
      }
    }
    ll res(0),mx(0);
    for(int i=1;i<=n;i++){
      if(find(i)!=i) continue;
      res+=val[i];mx=max(mx,val[i]);
    }
    if(w==2) res-=mx;
    else if(w==3) res+=mx;
    if(res>k) printf("Hell "); 
    else if(res) printf("Heaven ");
    else printf("Gensokyo ");
    printf("%lld\n",res);
  }
  return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值