はなたの日記

プログラミング(C言語)の勉強をしています。超初心者です。

ITP2_7_A Set: Search

問題
Set: Search | Aizu Online Judge

AOJに新しいコースが追加されていました。ITP2(Introduction to Programming 2)ということなのですが、
「Hello,World」から始まるITP1とは違って結構難しいです。なかなか解き終わりません。
多くはC++に標準実装されてる?ものが題材になっているのですが、手間をかけてCで頑張っています。
今回の問題もその一つで集合に関する問題です。

union-findでもやったように、集合は木構造で管理すると良さそうです。
実際、C++で標準実装されてるSet:searchも内部処理的には二分木だそうです。
というわけで、二分木を実装したのですが、入力に偏りがあると綺麗な二分木にならず、アクセス効率が悪くなりTLEとなってしまいます。
これを解決するために、平衡二分木を実装しました。具体的には、前回の記事にしたTreapを利用してみました。
今回、優先度は乱数を使って自分で与えることにしました。

#include<stdio.h>
#include<stdlib.h>
#include<time.h>

typedef struct node{
	int key;
	int priority;
	struct node *left;
	struct node *right;
}node;


int find(node *p,int x){

	while(p!=NULL){
		if(p->key == x)return 1;
		else if(p->key > x)p=p->left;
		else p=p->right;
	}
	
	return 0;
	
}


node * makenode(int x,int y){
	node *new=malloc(sizeof(node));
	new->key=x;
	new->priority=y;
	new->left=NULL;
	new->right=NULL;
	return new;
}

node *rightRotate(node *p){
	node *q=p->left;
	p->left=q->right;
	q->right=p;
	return q;
}

node *leftRotate(node *p){
	node *q=p->right;
	p->right=q->left;
	q->left=p;
	return q;
}


node* insert(node **t,int key,int priority){
	node *new;
	
	if((*t)==NULL)
		return new=makenode(key,priority);
	if ((*t)->key==key)
		return *t;
	
	if(key < (*t)->key){
		(*t)->left=insert(&(*t)->left,key,priority);
		if((*t)->priority < (*t)->left->priority)
			(*t)=rightRotate((*t));
	}
	else {
		(*t)->right=insert(&(*t)->right,key,priority);
		if((*t)->priority < (*t)->right->priority)
			(*t)=leftRotate((*t));
	}
	
	return *t;
}


int main(){
	int q,x,com;
	int num=0;
	node *root=NULL;
	srand((unsigned)time(NULL));
	
	scanf("%d",&q);
	
	for(int i=0;i<q;i++){
		scanf("%d %d",&com,&x);
		
		if(com==0){
			if(!find(root,x)){
				root=insert(&root,x,rand()%200001);
				num++;
			}
			printf("%d\n",num);
		}
		else {
			if(find(root,x))printf("1\n");
			else printf("0\n");
		}
		
	}
		
	return 0;
	
}

他の平衡二分木(AVL木)なども、いつか実装してみたいです。