离线:统计完所有输入数据在处理问题
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;
}