hdu3726

离线:统计完所有输入数据在处理问题

treap树

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<vector> 
#include<algorithm>
using namespace std;
struct node{
	node *ch[2];
	int s,v;
	int r;
	node (int v):v(v){
		ch[0]=ch[1]=NULL;r=rand();s=1;
	}//结构体赋值初始值定义
	bool operator < (const node& rhs)const{
	return r<rhs.r;
	} //定义运算符
	int cmp(int x) const
	{
		if(x==v)
		return -1;
		return x<v?0:1;
	 }//比较方便旋转 
	 void maintain()
	 {
	 	s=1;
	 	if(ch[0]!=NULL) s+=ch[0]->s;
	 	if(ch[1]!=NULL) s+=ch[1]->s; 
	  }//维护名次 
};//treap树节点 

const int maxc=500000+100;
const int maxn=20000+100;
const int maxm=60000+100;

struct one{
	char type;
	int x,p;
}ones[maxc];//题意单位数据结构 
int n,m,w[maxn],from[maxm],to[maxm];
bool removed[maxm];
int pa[maxn];
node* root[20005];//初始化数据结构
int qcnt;
 long long qtot;
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;
 } //旋转 指回原根节点位置 
 
 void insert(node* &o,int x)
 {
 	if(o==NULL)
 	o=new node(x);
 	else {
 		int d =(x<o->v?0:1);
 		insert (o->ch[d],x);
 		if(o->ch[d]>o)//定义了小于也就有了大于 
 		rotate(o,d^1);//维护平衡 
	 }
	 o->maintain();//维护名次 
  } //插入 

void remove(node* &o,int x)
{
	int d=o->cmp(x);
	if(d==-1)
	{
		node* u=o;
		if(o->ch[0]!=NULL&&o->ch[1]!=NULL)
		{
			int d2=(o->ch[0]>o->ch[1]?1:0);
			rotate(o,d2);
			remove(o->ch[d2],x);
		}
		else {
			if(o->ch[0]==NULL)
			{
				o=o->ch[1];
			}
		    else  o=o->ch[0];
			delete u;
		}
	 } 
	 else remove(o->ch[d],x);
	 if(o!=NULL)
	 {
	 	o->maintain();//操作要维护名次 
	 }
}//从以o树根删除一个x 


int findset(int x)
{
	if(x==pa[x])
	return x;
	return pa[x]=findset(pa[x]);
}



int kth(node* o,int k)
{
	if(o==NULL||k<=0||k>o->s) return 0;
	int s=(o->ch[1]==NULL?0:o->ch[1]->s);
	if(k==s+1) return o->v;
	else if(k<=s) return  kth(o->ch[1],k);
	else return kth(o->ch[0],k-s-1);
 } //找以o为根树的第k大 
 
 void mergeto(node* &src,node* &dest)
 {
 	if(src->ch[0]!=NULL) mergeto(src->ch[0],dest);
 	if(src->ch[1]!=NULL) mergeto(src->ch[1],dest);
 	insert (dest,src->v);
 	delete src;
 	src=NULL; 
 }
 //把一棵树连到另一个树上,树的访问是靠一个变动的节点访问;
 
 void removetree(node* &x)
 {
 	if(x->ch[0]!=NULL) removetree(x->ch[0]);
 	if(x->ch[1]!=NULL) removetree(x->ch[1]);
 	delete x;
 	x=NULL;
  } //树的访问只能从上往下,所以用递归的方法从上找到下从下删到上 
 
 void add_edge(int x)
 {
 	int u=findset(from[x]),v=findset(to[x]);//一组边可用同下标标记 
 	if(u!=v)
 	{
 		if(root[u]->s>root[v]->s)
 		{
 			pa[v]=u;
 			mergeto(root[v],root[u]);
		 }
		 else {
		 	pa[u]=v;
		 	mergeto(root[u],root[v]);
		 }
	 }
 }
 
 void query(int x,int k)
 {
 	qcnt++;
 	qtot+=kth(root[findset(x)],k);
 }//计算目标函数对值 
 void change(int x,int y)
 {
 	int u=findset(x);
 	remove(root[u],w[x]);
 	insert(root[u],y);
 	w[x]=y;
  } 
int main ()
{
	int kcase=0;
	while(scanf("%d%d",&n,&m)!=EOF&&n)
	{
		for(int i=1;i<=n;++i)
		scanf("%d",&w[i]);
		for(int i=1;i<=m;++i)
		{
			scanf("%d%d",&from[i],&to[i]);
		}
		memset(removed,false,sizeof(removed));
		int c=0;
		while(1)
		{
			char str[5];
			scanf("%s",str);
			int x,p=0,v=0;
			
			if(str[0]=='E')
			break;
			scanf("%d",&x);
			if(str[0]=='D')
			{
				
				removed[x]=true;
			}
			if(str[0]=='Q')
			{
				scanf("%d",&p);
			}
			if(str[0]=='C'){
				scanf("%d",&v);
				p=w[x];
				w[x]=v;
			}
			ones[c].type=str[0];
			ones[c].x=x;
			ones[c].p=p;
			c++;
		} 
		for(int i=1;i<=n;++i)
		{
			pa[i]=i;
			
			if(root[i]!=NULL)
			removetree(root[i]);
			root[i]=new node(w[i]);
		}
		for(int i=1;i<=m;++i)
		{
			if(!removed[i])
			add_edge(i);
		}
		qcnt=0;
		qtot=0;
		for(int i=c-1;i>=0;--i)
		{
			char type1=ones[i].type;
			if(type1=='D')
			add_edge(ones[i].x);
			if(type1=='Q')
			query(ones[i].x,ones[i].p);
			if(type1=='C')
			change(ones[i].x,ones[i].p);
		}
		printf("Case %d: %.6lf\n",++kcase,qtot/(double)qcnt);
	}
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值