• [bzoj1455]罗马游戏_左偏树_并查集


    罗马游戏 bzoj-1455

        题目大意:给你n个人,2种操作,m次操作:1.将i号士兵所在的集合的最小值删除 2.合并i和j两个士兵所在的团体

        注释:$1le nle 10^6$,$1le m le 10^5$。

          想法:又是GXZlegend讲课,可并堆中的左偏树。了解一下:

            一个具有堆性质的二叉树满足任意一个节点x中,dis[lson[x]]>=dis[rson[x]],其中,dis表示当前节点一直走右儿子的最长步数。合并是递归合并,我们通过递归处理一两个节点为根节点的左偏树的合并,显然左偏树的子树仍是左偏树。我们直接将一颗子树往另一颗子树的有儿子上挂,这两颗子树根节点大的(默认大根堆)当做合并后的根节点即可。

            附上合并代码... ...

    void merge(int x,int y)
    {
    	if(!x) return y;
    	if(!y) return x;
    	if(val[x]<val[y]) swap(x,y);
    	rson[x]=merge(rson[x],y);
    	if(dis[rson[x]]>dis[lson[x]]) swap(rson[x],lson[x]);
    	dis[x]=dis[rson[x]]+1;
    	return x;
    }

          至于这道题,我们用并查集维护每个人在哪个队伍里即可

        最后,附上丑陋的代码... ...

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define N 1000010 
    using namespace std;
    int fa[N],rson[N],lson[N],dis[N],w[N];
    bool k[N];
    int find(int x)
    {
    	return fa[x]==x?x:(fa[x]=find(fa[x]));
    }
    int merge(int x,int y)
    {
    	if(!x) return y;
    	if(!y) return x;
    	if(w[x]>w[y]) swap(x,y);
    	rson[x]=merge(rson[x],y);
    	if(dis[rson[x]]>dis[lson[x]])
    	{
    		swap(lson[x],rson[x]);
    	}
    	dis[x]=dis[rson[x]]+1;
    	return x;
    }
    inline int Kill(int x)
    {
    	if(k[x]) return 0;
    	x=find(x);
    	int t=merge(lson[x],rson[x]);
    	fa[x]=t;
    	fa[t]=t;
    	k[x]=true;
    	return w[x];
    }
    int main()
    {
    	int n,m;
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%d",&w[i]);
    	}
    	for(int i=1;i<=n;i++)
    	{
    		fa[i]=i;
    	}
    	char s[3];
    	scanf("%d",&m);
    	for(int i=1;i<=m;i++)
    	{
    		scanf("%s",s+1);
    		if(s[1]=='M')	
    		{
    			int x,y;
    			scanf("%d%d",&x,&y);
    			if(k[x]||k[y]) continue;
    			x=find(x),y=find(y);
    			if(x!=y) fa[x]=fa[y]=merge(x,y);
    			// fa[y]=x; 
    		}
    		else
    		{
    			int x;
    			scanf("%d",&x);
    			printf("%d
    ",Kill(x));
    		}
    	}
    	return 0;
    }
    /*
    2
    1 2
    3
    M 1 2
    K 1
    K 2
    */
    

        小结:错误都比较奇葩,在Kill的时候fa更新错了,merge函数在写的时候注意退出条件,不是任何时候都输出x的。

  • 相关阅读:
    Easyui datagrid 修改分页组件的分页提示信息为中文
    Easyui datagrid 实现表格记录拖拽
    Java:内部类
    算法导论:Trie字典树
    算法导论:找零钱问题
    lintcode:组成最大的数
    lintcode:验证二叉查找树
    lintcode:将二叉查找树转换成双链表
    lintcode:二叉树的路径和
    lintcode:字符串置换
  • 原文地址:https://www.cnblogs.com/ShuraK/p/8858477.html
Copyright © 2020-2023  润新知