[bzoj2733]永无乡 [bzoj1503]郁闷的出纳员

2733: [HNOI2012]永无乡

Time Limit: 10 Sec   Memory Limit: 128 MB
Submit: 1321   Solved: 693
[ Submit][ Status]

Description

永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示。某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达另一个岛。如果从岛 a 出发经过若干座(含 0 座)桥可以到达岛 b,则称岛 a 和岛 b 是连 通的。现在有两种操作:B x y 表示在岛 x 与岛 y 之间修建一座新桥。Q x k 表示询问当前与岛 x连通的所有岛中第 k 重要的是哪座岛,即所有与岛 x 连通的岛中重要度排名第 k 小的岛是哪 座,请你输出那个岛的编号。 
 

Input

输入文件第一行是用空格隔开的两个正整数 n 和 m,分别 表示岛的个数以及一开始存在的桥数。接下来的一行是用空格隔开的 n 个数,依次描述从岛 1 到岛 n 的重要度排名。随后的 m 行每行是用空格隔开的两个正整数 ai 和 bi,表示一开始就存 在一座连接岛 ai 和岛 bi 的桥。后面剩下的部分描述操作,该部分的第一行是一个正整数 q, 表示一共有 q 个操作,接下来的 q 行依次描述每个操作,操作的格式如上所述,以大写字母 Q 或B 开始,后面跟两个不超过 n 的正整数,字母与数字以及两个数字之间用空格隔开。 对于 20%的数据 n≤1000,q≤1000 
 
对于 100%的数据 n≤100000,m≤n,q≤300000 
 

Output

对于每个 Q x k 操作都要依次输出一行,其中包含一个整数,表 示所询问岛屿的编号。如果该岛屿不存在,则输出-1。 
 

Sample Input

5 1
4 3 2 5 1
1 2
7
Q 3 2
Q 2 1
B 2 3
B 1 5
Q 2 1
Q 2 4
Q 2 3

Sample Output

-1
2
5
1
2

  

/**************************************************************
    Problem: 2733
    User: _vampire_
    Language: C++
    Result: Accepted
    Time:2244 ms
    Memory:7480 kb
****************************************************************/
 
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std;
int n,m,q,fa[100001],a[100001],b[100001];
struct Node
{
    Node*ch[2];
    int r,v,s;
    Node(int v):v(v) {r=rand(); ch[0]=ch[1]=NULL;}
    int cmp(int x) const{
        if(x==v) return -1;
        else return (x>v?1:0);
    }
    void Maintain(){
        s=1;
        if(ch[0]!=NULL) s+=ch[0]->s;
        if(ch[1]!=NULL) s+=ch[1]->s;
    }
}*root[100001];
inline int find(int x)
{
    if(fa[x]!=x) fa[x]=find(fa[x]);
    return fa[x];
}
inline void rotate(Node* &o,int d)
{
    Node* k=o->ch[d^1]; o->ch[d^1]=k->ch[d]; k->ch[d]=o;
    o->Maintain(); k->Maintain(); o=k;
}
inline void insert(Node* &o,int x)
{
    if(o==NULL) o=new Node(x);
    else
    {
        int d=o->cmp(x);
        insert(o->ch[d],x);
        if(o->r < o->ch[d]->r) rotate(o,d^1);
    }
    o->Maintain();
}
inline void work(Node* &o1,Node* &o2)
{
    if(o2->ch[0]!=NULL) work(o1,o2->ch[0]);
    if(o2->ch[1]!=NULL) work(o1,o2->ch[1]);
    insert(o1,o2->v);
}
inline void Merge(int x,int y)
{
    if(root[x]->s>root[y]->s) work(root[x],root[y]), fa[y]=x;
    else work(root[y],root[x]), fa[x]=y;
}
inline int kth(Node* &o,int x)
{
    if(o==NULL||x>o->s||x<=0) return 0;
    int d=(o->ch[0]==NULL?0:o->ch[0]->s);
    if(x==d+1) return o->v;
    if(x<=d) return kth(o->ch[0],x);
    else return kth(o->ch[1],x-d-1);
}
int main()
{
    int i,j,x,y,r1,r2,xx;
    char aa;
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;++i) 
    {
        scanf("%d",&a[i]);
        fa[i]=i; b[a[i]]=i;
        insert(root[i],a[i]);
    }
    for(i=1;i<=m;++i)
    {
        scanf("%d%d",&x,&y);
        r1=find(x); r2=find(y);
        if(r1!=r2) Merge(r1,r2);
    }   
    scanf("%d",&q);
    for(i=1;i<=q;++i)
    {
        scanf("%*c%s%d%d",&aa,&x,&y);
        if(aa=='B')
        {
            r1=find(x); r2=find(y);
            if(r1!=r2) Merge(r1,r2);
        }
        else
        {
            xx=find(x); 
            if(root[xx]->s<y) printf("-1\n");
            else
            {               
                xx=kth(root[xx],y);
                printf("%d\n",b[xx]);
            }
        }
    }
}

1503: [NOI2004]郁闷的出纳员

Time Limit: 5 Sec   Memory Limit: 64 MB
Submit: 6841   Solved: 2395
[ Submit][ Status]

Description

OIER公司是一家大型专业化软件公司,有着数以万计的员工。作为一名出纳员,我的任务之一便是统计每位员工的工资。这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常,经常调整员工的工资。如果他心情好,就可能把每位员工的工资加上一个相同的量。反之,如果心情不好,就可能把他们的工资扣除一个相同的量。我真不知道除了调工资他还做什么其它事情。工资的频繁调整很让员工反感,尤其是集体扣除工资的时候,一旦某位员工发现自己的工资已经低于了合同规定的工资下界,他就会立刻气愤地离开公司,并且再也不会回来了。每位员工的工资下界都是统一规定的。每当一个人离开公司,我就要从电脑中把他的工资档案删去,同样,每当公司招聘了一位新员工,我就得为他新建一个工资档案。老板经常到我这边来询问工资情况,他并不问具体某位员工的工资情况,而是问现在工资第k多的员工拿多少工资。每当这时,我就不得不对数万个员工进行一次漫长的排序,然后告诉他答案。好了,现在你已经对我的工作了解不少了。正如你猜的那样,我想请你编一个工资统计程序。怎么样,不是很困难吧?

Input

Output

输出文件的行数为F命令的条数加一。对于每条F命令,你的程序要输出一行,仅包含一个整数,为当前工资第k多的员工所拿的工资数,如果k大于目前员工的数目,则输出-1。输出文件的最后一行包含一个整数,为离开公司的员工的总数。

Sample Input

9 10
I 60
I 70
S 50
F 2
I 30
S 15
A 5
F 1
F 2

Sample Output

10
20
-1
2

HINT

I命令的条数不超过100000 A命令和S命令的总条数不超过100 F命令的条数不超过100000 每次工资调整的调整量不超过1000 新员工的工资不超过100000


/**************************************************************
    Problem: 1503
    User: _vampire_
    Language: C++
    Result: Accepted
    Time:708 ms
    Memory:3260 kb
****************************************************************/
 
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std;
int n,k;
struct Node
{
    Node*ch[2];
    int r,v,num,s;
    Node(int v):v(v){ch[0]=ch[1]=NULL; r=rand(); num=1;};
    int cmp(int x) const {
        if(x==v) return -1;
        else return (x>v?1:0);
    }
    void Maintain(){
        s=num;
        if(ch[0]!=NULL) s+=ch[0]->s;
        if(ch[1]!=NULL) s+=ch[1]->s;
    }
};
Node* root; 
inline void rotate(Node* &o,int d)
{
    Node* k=o->ch[d^1]; o->ch[d^1]=k->ch[d]; k->ch[d]=o;
    o->Maintain(); k->Maintain(); o=k;
}
inline void insert(Node* &o,int x)
{
    if(o==NULL) o=new Node(x);
    else
    {
        int d=o->cmp(x);
        if(d==-1) o->num+=1;
        else
        {
            insert(o->ch[d],x);
            if(o->r < o->ch[d]->r) rotate(o,d^1);
        }
    }
    o->Maintain();
}
inline int rank(Node* &o,int x)
{
    int d=o->cmp(x);
    if(d==-1) return (o->ch[0]==NULL?1:o->ch[0]->s+1);
    else
    {
        if(d==0) return rank(o->ch[0],x);
        else return (rank(o->ch[1],x)+(o->ch[0]==NULL?o->num:o->ch[0]->s+o->num));
    }
}
inline void del(Node* &o,int x)
{
    int d=o->cmp(x);
    if(d==-1)
    {
        if(o->num==1)
        {
            if(o->ch[0]==NULL) o=o->ch[1];
            else if(o->ch[1]==NULL) o=o->ch[0];
            else
            {
                int d2=(o->ch[0]->r>o->ch[1]->r?1:0);
                rotate(o,d2); del(o->ch[d2],x);
            }
        }
        else o->num-=1;
    }   
    else del(o->ch[d],x);
    if(o!=NULL) o->Maintain();
}
inline int kth(Node* &o,int x)
{
    if(o==NULL||o->s<x||x<=0) return 0;
    int d=(o->ch[0]==NULL?0:o->ch[0]->s);
    if(d+1<=x&&x<=d+o->num) return o->v;
    if(x<=d) return kth(o->ch[0],x);
    else return kth(o->ch[1],x-d-o->num);
}
int main()
{
    int i,j,x,now=0,ans=0,sum=0,y,t;
    char a;
    scanf("%d%d",&n,&k);
    for(i=1;i<=n;++i)
    {
        scanf("%*c%s%d",&a,&x);
        if(a=='I')
        {
            if(x+now>=k) 
            {
                insert(root,x+now);
                sum+=1;
            }               
        }
        if(a=='A') now-=x,k-=x;
        if(a=='S') 
        {
            now+=x; k+=x;
            insert(root,k); t=rank(root,k);
            if(t>1)
            {
                ans+=t-1; sum=sum-t+1;
                for(j=1;j<=t-1;++j)
                {
                    y=kth(root,1); del(root,y);
                }
            }
            del(root,k);
        }
        if(a=='F') 
        {
             
            if(x>sum) printf("-1\n");
            else printf("%d\n",kth(root,sum-x+1)-now);
        }
    }
    printf("%d\n",ans);
}




模板题  :http://cojs.tk/cogs/problem/problem.php?pid=1829

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#define MM 2100000000
using namespace std;
int n,ans;
struct Node
{
	Node*ch[2];
	int v,r,s,num;
	Node(int v):v(v) { ch[0]=ch[1]=NULL; num=1; r=rand();}
	int cmp(int x) const {
		if(x==v) return -1;
		else return (x>v?1:0);
	}
	void Maintain(){
		s=num;
		if(ch[0]!=NULL) s+=ch[0]->s;
		if(ch[1]!=NULL) s+=ch[1]->s;
	}
};
Node* root;
inline void rotata(Node* &o,int d)
{
	Node* k=o->ch[d^1]; o->ch[d^1]=k->ch[d]; k->ch[d]=o;
	o->Maintain(); k->Maintain(); o=k;
}
inline void insert(Node* &o,int x)
{
	if(o==NULL) o=new Node(x);
	else 
	{
		int d=o->cmp(x);
		if(d==-1) o->num+=1;
		else 
		{
			insert(o->ch[d],x);
			if(o->r<o->ch[d]->r) rotata(o,d^1);
		}
	}
	o->Maintain();
}
inline void del(Node* &o,int x)
{
	int d=o->cmp(x);
	if(d==-1)
	{
		if(o->num==1)
		{
			if(o->ch[0]==NULL) o=o->ch[1];
			else if(o->ch[1]==NULL) o=o->ch[0];
			else 
			{
				int d2=(o->ch[1]->r > o->ch[0]->r?0:1);
				rotata(o,d2); del(o->ch[d2],x);
			}
		}
		else o->num-=1;
	}
	else del(o->ch[d],x);
	if(o!=NULL) o->Maintain();
}
inline int rank(Node* &o,int x)
{
	int d=o->cmp(x);
	if(d==-1) return (o->ch[0]==NULL?1:o->ch[0]->s+1);
	else 
	{
		if(d==0) return rank(o->ch[0],x);
		else return (rank(o->ch[1],x)+(o->ch[0]==NULL?o->num:o->ch[0]->s+o->num));
	}
}
inline int kth(Node* &o,int x)
{
	if(o==NULL||o->s<x||x<=0) return 0;
	int d=(o->ch[0]==NULL?0:o->ch[0]->s);
	if(d+1<=x&&x<=d+o->num) return o->v;
    if(x<=d) return kth(o->ch[0],x);
    else return kth(o->ch[1],x-d-o->num);
}
inline void pre(Node* &o,int x)
{
	if(x<=o->v)
	{
		if(o->ch[0]!=NULL) pre(o->ch[0],x);
    }
    else 
    {
    	ans=max(ans,o->v);
    	if(o->ch[1]!=NULL) pre(o->ch[1],x);
    }
}
inline void sub(Node* &o,int x)
{
	if(x>=o->v)
	{
		if(o->ch[1]!=NULL) sub(o->ch[1],x);
	}
	else
	{
		ans=min(ans,o->v);
		if(o->ch[0]!=NULL) sub(o->ch[0],x);
	}
}
int main()
{
	freopen("phs.in","r",stdin);
	freopen("phs.out","w",stdout);
	int i,j,x,t;
	scanf("%d",&n);
	for(i=1;i<=n;++i)
	{
		scanf("%d%d",&t,&x);
		if(t==1) insert(root,x);
		if(t==2) del(root,x);
		if(t==3) printf("%d\n",rank(root,x));
		if(t==4) printf("%d\n",kth(root,x));
		if(t==5)
		{
		    ans=-MM; pre(root,x);
			printf("%d\n",ans);	
		}
		if(t==6)
		{
			ans=MM; sub(root,x);
			printf("%d\n",ans);
		}
	}
}



        在做题的过程中还是有些体会的:

          ①:因为我的treap用到的是指针操作,所以有些地方写残了就很容易炸,在写代码的时候要更加严谨,多考虑和判断一些情况。

          ②:第二点就是在做有些难度稍大的题的时候,我们往往可以把这个题分解成之前学过的一些算法和结构的形式,这样我们就可以把一道看似有些难度的变成一道比较简单的题了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值