为什么大家写200行的题我要写400行才过啊QAQ。。。。。
详解在代码注释中 这题真的写了好久 从自己写完到、调试到和刘汝佳的标程核对 前后花了半上午+一下午时间QAQ
程序见下 很长确实,但是可读性我觉得比别人是高了很多的
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
//AC
using namespace std;
#define mem(x) memset(x,0,sizeof(x))
const int maxn=2*100000+50;
const int maxm=6*100000+50;
const int maxc=5*1000000+50;
int n,m;
//0表示左旋 1表示右旋
struct comment
{
char type;
int x,p;
comment(char type=0,int x=0,int p=0)
{
this->type=type;
this->x=x;
this->p=p;
}
void ini()
{
type=0;
x=0;
p=0;
}
}c[maxc];
struct node
{
int r;
int siz;
int v;
node* ch[2];//0表示左儿子 1表示右儿子
node(int v)
{
this->v=v;
this->siz=1;/
this->ch[0]=this->ch[1]=NULL;
this->r=rand();
}
int cmp(int x)const
{
if(x==v) return -1;
else return x>v?1:0;
}
};
node* root[maxn];
int f[maxn];//并查集相关
int getf(int x)
{
return f[x]==x?f[x]:(f[x]=getf(f[x]));//注意这里要更新f[x]本身
}
void maintain(node* &v)
{
int s=1;
if(v->ch[0]!=NULL)
{
s+=v->ch[0]->siz;
}
if(v->ch[1]!=NULL)
{
s+=v->ch[1]->siz;
}
v->siz=s;
}
void rotate(node* &o,int d)//旋转操作
{
node *k=o->ch[d^1];
o->ch[d^1]=k->ch[d];
k->ch[d]=o;
maintain(o);
maintain(k);
o=k;
}
void insert(node* &o,int x)
{
if(o==NULL)
{
o=new node(x);
}
else
{
int d=(o->v)>x?0:1;//一定要注意用cmp比较的话相等的两点会被忽略!
//这与之前写的treap不同,因为之前的treap不用管相等的元素,这个错误调了很长时间,望注意
insert(o->ch[d],x);
if((o->ch[d]->r)>o->r)
{
rotate(o,d^1);
}
if(o!=NULL)
{
maintain(o);
}
}
}
void remove(node* &o,int x)
{
int d=o->cmp(x);
if(d==-1)//就是节点本身的情况
{
if(o->ch[1]!=NULL && o->ch[0]!=NULL)
{
int d2=((o->ch[0]->r)>(o->ch[1]->r)?1:0);
rotate(o,d2);
remove(o->ch[d2],x);
}
else if(o->ch[1]==NULL)
{
o=o->ch[0];
}
else
{
o=o->ch[1];
}
if(o!=NULL) maintain(o);
}
else
{
remove(o->ch[d],x);
if(o!=NULL) maintain(o);
}
}
int kth(node* &o,int k)//返回该树根下的第k大的数
{
if(o==NULL || k<=0 || o->siz<k)/三个条件?->是的,题目说有不合法询问
{
return 0;
}
int s=(o->ch[1]==NULL?0:o->ch[1]->siz);
if(s+1==k)
{
return o->v;
}
else if(s>=k)
{
return kth(o->ch[1],k);//因为没有算入本身的节点,所以不用改变k的值
}
else
{
return kth(o->ch[0],k-s-1);
}
}
int from[maxm],to[maxm];///树相关、询问相关
int weight[maxn];
bool removed[maxn];//记录删除节点
void getmergeto(node* &par,node* &all)//将par树合并到all
{
if(par->ch[0]!=NULL)
{
getmergeto(par->ch[0],all);
}
if(par->ch[1]!=NULL)
{
getmergeto(par->ch[1],all);
}
if(par!=NULL) maintain(par);
insert(all,par->v);
delete par;
par=NULL;//不加这一句会怎样啊//delete以后存的是垃圾值,不归零就可能出错(因为以后可能访问)
if(all!=NULL) maintain(all);
}
void removetree(node* &o)//把o及以下所有节点全部删除
{
if(o->ch[0]!=NULL)
{
removetree(o->ch[0]);
}
if(o->ch[1]!=NULL)
{
removetree(o->ch[1]);
}
if(o!=NULL) maintain(o);
delete o;
o=NULL;//一旦调用delete 一定要把原指针清零
}
void changeweight(int x,int v)//改变x号的权值至v
{
int u=getf(x);
remove(root[u],weight[x]);
insert(root[u],v);
weight[x]=v;
}
int query(int x,int k)//与x连通的点中第2大的权值
{
node* o=root[getf(x)];
return kth(o,k);
}
void addedge(int x)
{
int u=from[x];
int v=to[x];
u=getf(u);
v=getf(v);
if(u!=v)//注意:必须要在u!=v的情况下进行
{
if((root[u]->siz)>(root[v]->siz))
{
f[v]=u;//
getmergeto(root[v],root[u]);
/*
if(root[u]!=NULL)
{
maintain(root[u]);
}
*/
}
else
{
f[u]=v;//
getmergeto(root[u],root[v]);
/*
if(root[v]!=NULL)
{
maintain(root[v]);
}
*/
}
}
}
void ini()
{
for(int i=0;i<maxn;i++)
{
f[i]=i;
}
mem(from);
mem(to);
mem(weight);
mem(removed);
for(int i=0;i<maxn;i++)
{
root[i]=NULL;
}
for(int i=0;i<maxm;i++)
{
c[i].ini();
}
}
int main()
{
int kas=0;
while(scanf("%d%d",&n,&m)==2)
{
kas++;
if(n==0)
{
break;
}
ini();
for(int i=1;i<=n;i++)
{
scanf("%d",&weight[i]);
}
for(int i=1;i<=m;i++)
{
scanf("%d%d",&from[i],&to[i]);
}
int qnum=0;//记录所有指令数
int qsum=0;//记录q指令个数
while(1)
{
char type;
int x=0,p=0;
scanf(" %c",&type);
if(type=='E')
{
break;
}
else if(type=='D')
{
scanf("%d",&x);//删除id为x的边
removed[x]=true;
}
else if(type=='Q')
{
scanf("%d%d",&x,&p);
qsum++;
}
else if(type=='C')
{
scanf("%d%d",&x,&p);
int v=weight[x];
weight[x]=p;
p=v;
}
c[qnum++]=comment(type,x,p);
}
for(int i=1;i<=n;i++)
{
f[i]=i;
if(root[i]!=NULL)
{
removetree(root[i]);
}
root[i]=new node(weight[i]);//一定要在这里重新分配内存
}
for(int i=1;i<=m;i++)
{
if(!removed[i])
{
addedge(i);
}
}
double ans=0;
for(int i=qnum-1;i>=0;i--)
{
char ty=c[i].type;
if(ty=='Q')
{
ans+=query(c[i].x,c[i].p);
}
else if(ty=='C')
{
changeweight(c[i].x,c[i].p);
}
else if(ty=='D')
{
removed[c[i].x]=false;
addedge(c[i].x);
}
}
printf("Case %d: %.6lf\n",kas,(double)ans/(double)qsum);
}
return 0;
}