左偏树(BZOJ2809)

思路:dfs,如果总和超过M,就把树根丢掉

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
#define null 0
using namespace std;
typedef long long LL;
const int maxn=400010;
int N;
LL L[maxn],M,ans;
int head[maxn];
int num;
struct E
{
    int v,next;
}edge[maxn];
void add_edge(int fa,int v)
{
    edge[num].v=v;
    edge[num].next=head[fa];
    head[fa]=num++;
}
struct Node
{
    LL key,L,sum;
    int l,r,f,dis;
    int s;
}tree[maxn];
//得到节点标号为r的节点的跟节点编号
int getroot(int r)
{
    if(r==null)return r;
    while(tree[r].f!=null)
        r=tree[r].f;
    return r;
}
//合并两个左偏树
int merge(int rx,int ry)
{
    if(rx==null)return ry;
    if(ry==null)return rx;
    if(tree[rx].key<tree[ry].key)swap(rx,ry);
    int r=merge(tree[rx].r,ry);
    tree[rx].r=r;
    tree[r].f=rx;

    if(tree[rx].l==null||tree[r].dis>tree[tree[rx].l].dis)
        swap(tree[rx].l,tree[rx].r);
    if(tree[rx].r==null)tree[rx].dis=0;
    else tree[rx].dis=tree[tree[rx].r].dis+1;
    tree[rx].sum=tree[tree[rx].l].sum+tree[tree[rx].r].sum+tree[rx].key;
    tree[rx].s=tree[tree[rx].l].s+tree[tree[rx].r].s+1;
    return rx;
}
//插入节点,节点编号为r,插入后的节点为root
int insert(int r,int key,int root)
{
    tree[r].key=key;
    tree[r].l=tree[r].r=tree[r].f=null;
    tree[r].dis=0;
    return root=merge(root,r);
}
//删除编号为o的点
int del(int o)
{
    if(o==null)return o;
    int l=tree[o].l;
    int r=tree[o].r;
    int y=tree[o].f;
    int x;
    tree[o].l=tree[o].r=tree[o].f=null;
    tree[x=merge(l,r)].f=y;
    if(y!=null&&tree[y].l==o)tree[y].l==x;
    if(y!=null&&tree[y].r==o)tree[y].r==x;
    for(;y!=null;x=y,y=tree[y].f)
    {
        if(tree[tree[y].l].dis<tree[tree[y].r].dis)
            swap(tree[y].l,tree[y].r);
        if(tree[tree[y].r].dis+1==tree[y].dis)
            break;
        tree[y].dis=tree[tree[y].r].dis+1;
    }
    if(x!=null)return getroot(x);
    else return getroot(y);
}
Node top(int r)
{
    return tree[r];
}
//返回最值
Node pop(int &o)
{
    Node out=tree[o];
    int l=tree[o].l,r=tree[o].r;
    tree[o].l=tree[o].r=tree[o].f=null;
    tree[l].f=tree[r].f=null;
    o=merge(l,r);
    return out;
}
//编号为o的节点加上val
int add(int o,int val)
{
    if(o==null)return o;
    if(tree[o].l==null&&tree[o].r==null&&tree[o].f==null)
    {
        tree[o].key+=val;
        return o;
    }
    int key=tree[o].key+val;
    int rt=del(o);
    return insert(o,key,rt);
}
int dfs(int u)
{
    int root=u;
    tree[root].sum=tree[root].key;
    tree[root].s=1;
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].v;
        int newroot=dfs(v);
        root=merge(root,newroot);
    }
    while(tree[root].sum>M)
        root=merge(tree[root].l,tree[root].r);
    ans=max(ans,L[u]*tree[root].s);
    return root;
}
int main()
{
    while(scanf("%d%d",&N,&M)!=EOF)
    {
        int st=0;
        LL c;
        int u;
        num=0;
        memset(head,-1,sizeof(head));
        for(int i=1;i<=N;i++)
        {
            scanf("%d%lld%lld",&u,&c,&L[i]);
            if(!u)st=i;
            else add_edge(u,i);
            tree[i].key=c;
            tree[i].l=L[i];
            tree[i].l=tree[i].r=tree[i].f=null;
            tree[i].sum=c;
            tree[i].s=1;
        }
        ans=0;
        dfs(1);
        printf("%lld\n",ans);
    }
    return 0;
}

下面的代码转自: bzoj2809

#include<cstdio>
#include<iostream>
#define N 100100
#define MAX(a,b) (((a)>(b))?(a):(b))
typedef unsigned long long LL;
template<class T>
T read(T &x)
{
    x=0;
    static char c(0);
    for(;c<'0'||c>'9';c=getchar());
    for(;c>='0'&&c<='9';c=getchar())(x*=10)+=c-'0';
    return x;
}
class node
{
    public:
        int val,dis,size;
        LL sum;
        node* son[2];
}*tree[N],hh[N];
struct db
{
    int next,v;
}edges[N];
int n,m,tot,point[N];
LL lead[N],ans(0);
inline void addedge(int u,int v)
{
    if(!u)return;
    static int en(0);
    edges[++en].next=point[u];edges[en].v=v;point[u]=en;
}
inline void newnode(node* &x,int val)
{
    x=hh+(++tot);
    x->sum=x->val=val;
    x->size=1;x->dis=0;
    x->son[0]=x->son[1]=hh;
}
inline node* merge(node* a,node* b)
{
    if(a==hh)return b;
    if(b==hh)return a;
    if(a->val<b->val)std::swap(a,b);
    a->son[1]=merge(a->son[1],b);
    if(a->son[0]->dis<a->son[1]->size)
        std::swap(a->son[0],a->son[1]);
    a->dis=a->son[1]->dis+1;
    a->sum=a->son[0]->sum+a->son[1]->sum+a->val;
    a->size=a->son[0]->size+a->son[1]->size+1;
    return a;
}
inline node* dfs(int u)
{
    for(int i=point[u];i;i=edges[i].next)
        tree[u]=merge(tree[u],dfs(edges[i].v));
    while((tree[u]->sum)>m)
        tree[u]=merge(tree[u]->son[0],tree[u]->son[1]);
    ans=MAX(ans,lead[u]*tree[u]->size);
    return tree[u];
}
int main()
{
    read(n);read(m);
    hh->sum=hh->val=hh->size=0;hh->dis=-1;
    hh->son[0]=hh->son[1]=hh;
    for(int i=1,tmp;i<=n;i++)
    {
        addedge(read(tmp),i);
        newnode(tree[i],read(tmp));
        read(lead[i]);
    }
    dfs(1);
    printf("%lld\n",ans);
    return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值