• 可并堆


    可并堆

    可并堆,又称为左偏树,满足从一个节点一直向左儿子走比一直向右儿子走距离更长。

    这样,它就满足了往右走最多log次,也就是每次合并的时间复杂度为O(log)

    合并:将一个合并到另一个的右儿子上,合并的同时满足堆的所有性质。

    BZOJ1455罗马游戏:

    维护小根堆,每次合并的时候讲大的合并到小的的右儿子上。

    可并堆例题,没有什么多说的,权值线段树合并应该也可以做。

    附上代码:

    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <cstring>
    #include <iostream>
    #include <queue>
    #include <cstdlib>
    using namespace std;
    #define N 1000005
    int fa[N],n,Q;
    char s[2];
    struct node
    {
    	int ls,rs,x,dis;
    }mp[N];
    int merge(int x,int y)
    {
    	if(!x)return y;
    	if(!y)return x;
    	if(mp[x].x>mp[y].x)swap(x,y);
    	mp[x].rs=merge(mp[x].rs,y);
    	if(mp[mp[x].ls].dis<mp[mp[x].rs].dis)swap(mp[x].ls,mp[x].rs);
    	mp[x].dis=mp[mp[x].rs].dis+1;
    	return x;
    }
    int find(int x)
    {
    	if(fa[x]==x)return x;
    	return fa[x]=find(fa[x]);
    }
    bool vis[N];
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)
    	{
    		fa[i]=i;
    		scanf("%d",&mp[i].x);
    	}
    	scanf("%d",&Q);
    	while(Q--)
    	{
    		int x,y;
    		scanf("%s%d",s,&x);
    		if(s[0]=='M')
    		{
    			scanf("%d",&y);
    			if(vis[x]||vis[y])continue;
    			int fx=find(x),fy=find(y);
    			if(fx==fy)continue;
    			fa[fx]=fa[fy]=merge(fx,fy);
    		}else
    		{
    			if(vis[x])
    			{
    				printf("0
    ");
    				continue;
    			}
    			int fx=find(x);
    			printf("%d
    ",mp[fx].x);
    			fa[fx]=fa[mp[fx].ls]=fa[mp[fx].rs]=merge(mp[fx].ls,mp[fx].rs);
    			mp[fx].rs=mp[fx].ls=0;
    			vis[fx]=1;
    		}
    	}
    	return 0;
    }
    

    BZOJ2809: [Apio2012]dispatching

    我们考虑,维护大根堆,费用大于M就弹出堆顶,在给出的树上完成操作,用dfs实现。

    附上代码:

    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <queue>
    using namespace std;
    #define N 100005
    #define ll long long
    struct no
    {
        int to,next;
    }e[N];
    int head[N],cnt,a[N],b[N],fa[N],n,m;
    struct node
    {
        int ls,rs,x,dis;
    }mp[N];
    void add(int x,int y)
    {
        e[cnt].to=y;
        e[cnt].next=head[x];
        head[x]=cnt++;
        return ;
    }
    int find(int x)
    {
        if(x==fa[x])return x;
        return fa[x]=find(fa[x]);
    }
    int merge(int x,int y)
    {
        if(!x)return y;
        if(!y)return x;
        if(mp[x].x<mp[y].x)swap(x,y);
        mp[x].rs=merge(mp[x].rs,y);
        if(mp[mp[x].ls].dis<mp[mp[x].rs].dis)swap(mp[x].ls,mp[x].rs);
        mp[x].dis=mp[mp[x].rs].dis+1;
        return x;
    }
    ll ans,sum[N];
    int siz[N];
    void dfs(int x,int from)
    {
        sum[x]=a[x];
        siz[x]=1;
        for(int i=head[x];i!=-1;i=e[i].next)
        {
            int to1=e[i].to;
            if(to1!=from)
            {
                dfs(to1,x);
                sum[x]+=sum[to1];
                int fx=find(x),fy=find(to1);
                fa[fx]=fa[fy]=merge(fx,fy);
                siz[x]+=siz[to1];
            }
        }
        while(sum[x]>m)
        {
            siz[x]--;
            int fx=find(x);
            sum[x]-=mp[fx].x;
            mp[fx].x=0;
            fa[fx]=fa[mp[fx].ls]=fa[mp[fx].rs]=merge(mp[fx].ls,mp[fx].rs);
        }
        ans=max(1ll*b[x]*siz[x],ans);
        return ;
    }
    int main()
    {
        memset(head,-1,sizeof(head));
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            fa[i]=i;
            int x;
            scanf("%d%d%d",&x,&a[i],&b[i]);
            mp[i].x=a[i];
            if(!x)continue;
            add(x,i);
        }
        dfs(1,0);
        printf("%lld
    ",ans);
        return 0;
    }
    

    BZOJ3011: [Usaco2012 Dec]Running Away From the Barn

    这题方法不少,可并堆可以实现,每次将距离大于L的弹出堆顶,同时需要记录堆中元素个数,比较水,记得开long long

    附上代码:

    #include <cstdio>
    #include <algorithm>
    #include <iostream>
    #include <queue>
    #include <cmath>
    #include <cstring>
    #include <cstdlib>
    using namespace std;
    #define N 200005
    #define ll long long
    struct node
    {
        int dis,ls,rs;
        ll x;
    }mp[N];
    struct no
    {
        int to,next;
        ll val;
    }e[N];
    int head[N],cnt;
    void add(int x,int y,ll z)
    {
        e[cnt].to=y;
        e[cnt].val=z;
        e[cnt].next=head[x];
        head[x]=cnt++;
        return ;
    }
    int fa[N],n,siz[N];
    ll dep[N],L;
    int merge(int x,int y)
    {
        if(!x)return y;
        if(!y)return x;
        if(mp[x].x<mp[y].x)swap(x,y);
        mp[x].rs=merge(mp[x].rs,y);
        if(mp[mp[x].rs].dis>mp[mp[x].ls].dis)swap(mp[x].ls,mp[x].rs);
        mp[x].dis=mp[mp[x].rs].dis+1;
        return x;
    }
    int find(int x)
    {
        if(x==fa[x])return x;
        return fa[x]=find(fa[x]);
    }
    void dfs(int x,int from)
    {
        siz[x]=1;
        for(int i=head[x];i!=-1;i=e[i].next)
        {
            int to1=e[i].to;
            if(to1!=from)
            {
                mp[to1].x=dep[to1]=dep[x]+e[i].val;
                dfs(to1,x);
                siz[x]+=siz[to1];
                int fx=find(x),fy=find(to1);
                fa[fx]=fa[fy]=merge(fx,fy);
            }
        }
        int fx=find(x);
        while(mp[fx].x>L+dep[x])
        {
            fa[fx]=fa[mp[fx].ls]=fa[mp[fx].rs]=merge(mp[fx].ls,mp[fx].rs);
            siz[x]--;
            fx=find(x);
        }
        return ;
    }
    int main()
    {
        fa[1]=1;
        memset(head,-1,sizeof(head));
        scanf("%d%lld",&n,&L);
        for(int i=2;i<=n;i++)
        {
            fa[i]=i;
            int x;
            ll y;
            scanf("%d%lld",&x,&y);
            add(x,i,y);
        }
        dfs(1,0);
        for(int i=1;i<=n;i++)
        {
            printf("%d
    ",siz[i]);
        }
        return 0;
    }
    
    

    BZOJ4003: [JLOI2015]城池攻占

    我写过这题的题解,就不重复了,附上链接:https://www.cnblogs.com/Winniechen/p/8890801.html

    BZOJ3252: 攻略

    网上的题解给的都是线段树+dfs序,挺裸的,可并堆也可以实现,跑的飞起,代码精悍。附上链接:https://www.cnblogs.com/Winniechen/p/8990559.html

  • 相关阅读:
    Dev XtraTreeList 学习
    DataGridView单元格显示GIF图片
    如何在.NET上处理二维码
    设计模式之UML类图的常见关系(一)
    .NET常用操作小知识
    Sql Server 存储过程使用技巧
    WinForm中如何判断关闭事件来源于用户点击右上角的“关闭”按钮
    WinFrom 安装包制作
    DBHelper数据库操作类(二)
    spring cloud zipkin
  • 原文地址:https://www.cnblogs.com/Winniechen/p/9095448.html
Copyright © 2020-2023  润新知