zoukankan      html  css  js  c++  java
  • [bzoj2733][HNOI2012]永无乡_权值线段树_线段树合并

    永无乡 bzoj-2733 HNOI-2012

    题目大意题目链接

    注释:略。


    想法

    它的查询操作非常友善,就是一个联通块内的$k$小值。

    故此我们可以考虑每个联通块建一棵权值线段树。

    这样的话每次修改采用线段树启发式合并,查询暴力走权值线段树即可。

    Code:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define N 100010 
    using namespace std;
    struct Node
    {
    	int ls,rs,size;
    	Node() {ls=rs=size=0;}
    }a[N*50];
    int rt[N],fa[N],cnt,val[N],re[N];
    int find(int x) {return fa[x]==x?x:fa[x]=find(fa[x]);}
    int merge(int x,int y)
    {
    	if(!x||!y) return x|y;
    	a[x].size+=a[y].size;
    	a[x].ls=merge(a[x].ls,a[y].ls); a[x].rs=merge(a[x].rs,a[y].rs);
    	return x;
    }
    int query(int x,int k,int l,int r)
    {
    	if(l==r) return l;
    	int ls=a[x].ls,rs=a[x].rs;
    	int mid=(l+r)>>1;
    	if(k<=a[ls].size) return query(ls,k,l,mid);
    	else return query(rs,k-a[ls].size,mid+1,r);
    }
    int build(int x,int l,int r)
    {
    	// printf("%d %d %d
    ",x,l,r);
    	int p=++cnt;
    	a[p].size=1;
    	if(l==r) return p;
    	int mid=(l+r)>>1;
    	if(x<=mid) a[p].ls=build(x,l,mid);
    	else a[p].rs=build(x,mid+1,r);
    	return p;
    }
    int main()
    {
    	int n,m; cin >> n >> m ; for(int i=1;i<=n;i++) scanf("%d",&val[i]),re[val[i]]=i,fa[i]=i;
    	for(int i=1;i<=n;i++) rt[i]=build(val[i],1,n);
    	// for(int i=1;i<=n;i++) cout << rt[i] << " " ; puts("");
    	for(int x,y,i=1;i<=m;i++)
    	{
    		scanf("%d%d",&x,&y); x=find(x); y=find(y);
    		if(x!=y)
    		{
    			rt[x]=merge(rt[x],rt[y]);
    			fa[y]=x;
    		}
    	}
    	// for(int i=1;i<=n;i++) printf("%d ",find(i)); puts("");
    	int q; cin >> q ; while(q--)
    	{
    		char opt[10]; int x,y; scanf("%s%d%d",opt,&x,&y);
    		if(opt[0]=='B')
    		{
    			x=find(x); y=find(y);
    			if(x!=y)
    			{
    				rt[x]=merge(rt[x],rt[y]); fa[y]=x;
    			}
    		}
    		else
    		{
    			x=find(x);
    			if(y>a[rt[x]].size) puts("-1");
    			else printf("%d
    ",re[query(rt[x],y,1,n)]);
    		}
    	}
    	return 0;
    }
    

    小结:这题是别人好几个月之前写的,当时觉得贼高级现在一看原来是sb题.....

  • 相关阅读:
    Linux 关机和重启命令
    Linux ubuntu安装ftp服务器
    C++ map和unsorted_map底层实现
    C++中的那些容器在使用时,哪些情况下迭代器会失效
    虚函数表的构造
    C++容器 priority_queue,堆的实现
    c++11中的move是否会改变对象的地址
    (转)关于linux中内核编程中结构体的赋值操作(结构体指定初始化)
    无参方法
    类和对象
  • 原文地址:https://www.cnblogs.com/ShuraK/p/10163417.html
Copyright © 2011-2022 走看看