伸展树的启发式合并

今年APIO被启发式合并坑了有木有啊!!!!

于是回家就写启发式合并啊!!!!

WA了N次最后发现语句写反了,伤不起啊有木有!!!!

无非就是把原节点链表拆开然后插入有木有啊!!!!

于是我就直接贴代码了啊!!!!

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#define fa(x) tree[x].fa
#define data(x) tree[x].data
#define sum(x) tree[x].sum
#define son(x) tree[x].size
#define l(x) tree[x].l
#define r(x) tree[x].r

using namespace std;

struct node
{
 int fa,data,size,l,r;
 long long sum;
} tree[100001];

vector<int> graph[100001];
vector<int> seq;
int l[100001],c[100001],n,m,b,root[100001],ans[100001];

inline void update(int x)
{
 if (x!=0)
  son(x)=son(l(x))+son(r(x))+1,sum(x)=sum(l(x))+sum(r(x))+data(x);
}

inline void right_rotate(int x)
{
 int y=fa(x),tmp=r(x);
 if (l(fa(y))==y)
  l(fa(y))=x;
 else
  r(fa(y))=x;
 fa(x)=fa(y),fa(y)=x,l(y)=tmp,fa(tmp)=r(x)=y;
 update(y),update(x);
}

inline void left_rotate(int x)
{
 int y=fa(x),tmp=l(x);
 if (l(fa(y))==y)
  l(fa(y))=x;
 else
  r(fa(y))=x;
 fa(x)=fa(y),fa(y)=x,r(y)=tmp,fa(tmp)=l(x)=y;
 update(y),update(x);
}

inline void splay(int rr,int x,int pos)
{
 int f=fa(rr);
 while (fa(x)!=f)
  {
   int y=fa(x),z=fa(y);
   if (z==f)
    {
     if (l(y)==x)
      right_rotate(x);
     else
      left_rotate(x);
     break;
    }
   if (l(z)==y)
    {
     if (l(y)==x)
      right_rotate(y),right_rotate(x);
     else
      left_rotate(x),right_rotate(x);
    }
   else
    {
     if (l(y)==x)
      right_rotate(x),left_rotate(x);
     else
      left_rotate(y),left_rotate(x);
    }
  }
 if (rr==root[pos])
  root[pos]=x;
}

inline void insert(int pos,int x)
{
 l(x)=r(x)=fa(x)=0;
 int val=data(x);
 if (pos==0)
  {
   son(x)=1,sum(x)=data(x),root[pos]=x;
   return;
  }
 int k=root[pos];
 while (1)
  {
   if (val<data(k))
    {
     if (l(k)==0)
      break;
     k=l(k);
    }
   else
    {
     if (r(k)==0)
      break;
     k=r(k);
    }
  }
 son(k)++,fa(x)=k,sum(k)+=data(x),sum(x)=data(x),son(x)=1;
 if (val<data(k))
  l(k)=x;
 else
  r(k)=x; 
 splay(root[pos],x,pos);
}

void search(int x)
{
 if (x==0)
  return;
 seq.push_back(x);
 search(l(x)),search(r(x));
} 

inline void comb(int t,int s)
{
 seq.clear();
 search(root[s]);
 for (int i=0;i<seq.size();i++)
  insert(t,seq[i]);
} 

inline int get_ans(int r)
{
 int x=root[r],ans=0,temp=m;
 while (x!=0 && temp>0)
  {
   if (sum(x)-sum(r(x))>temp)
    x=l(x);
   else
    temp-=(sum(x)-sum(r(x))),ans+=(son(l(x))+1),x=r(x);
  }
 return ans;
}

void dfs(int r)
{
 int temp=0,k=0;
 for (int i=0;i<graph[r].size();i++)
  {
   dfs(graph[r][i]);
   if (temp<son(root[graph[r][i]]))
    k=root[graph[r][i]],temp=son(root[graph[r][i]]);
  }
 for (int i=0;i<graph[r].size();i++)
  {
   int j=graph[r][i];
   if (j==k)
    continue;
   comb(k,j);
  }
 insert(k,r),root[r]=r;
 ans[r]=get_ans(r);
}
 
int main()
{
 freopen("dispatching.in","r",stdin);
 freopen("dispatching.out","w",stdout);
 scanf("%d%d",&n,&m);
 for (int i=1;i<=n;i++)
  {
   scanf("%d%d%d",&b,c+i,l+i);
   graph[b].push_back(i),data(i)=c[i];
  }
 dfs(1);
 long long temp=0,res=0;
 for (int i=1;i<=n;i++)
  {
   temp=ans[i]*l[i];
   res=max(res,temp);
  }
 printf("%lld\n",res);
 return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值