题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=3726
题目大意:给出一幅无向边构成的图,每个点有一个点权。有3种操作:删掉一条边,更改一个点的点权,以及查询一个点所在的连通块的第k大点权。
分析:这里我们可以通过对每一个连通块维护一棵treap在log(n)的时间内完成操作2,3,至于操作1,我们发现分离比较难办,于是我们考虑离线读入,然后从后往前做,逐个合并treap。这里如果采用启发式合并,时间复杂度O(n*log^2(n))。
CODE:
#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<stdio.h>
#include<algorithm>
#include<ctime>
using namespace std;
const int maxn=40010;
const int maxm=120010;
const int maxw=800100;
const int lg=22;
struct Tnode
{
int val,fix,Size;
Tnode *lson,*rson;
int Lsize() { return lson?lson->Size:0; }
int Rsize() { return rson?rson->Size:0; }
void Get_size() { Size=Lsize()+Rsize()+1; }
} tree[maxn*lg];
Tnode *Root[maxn];
int fa[maxn];
int cur;
int u[maxm];
int v[maxm];
int V[maxn];
bool use[maxm];
struct data
{
int id,a,b;
} work[maxw];
char op[10];
int n,m,w,numq;
long long sum;
int Case=0;
Tnode *New_node(int nv)
{
cur++;
tree[cur].val=nv;
tree[cur].fix=rand();
tree[cur].Size=1;
tree[cur].lson=tree[cur].rson=NULL;
return tree+cur;
}
void Right_turn(Tnode *&P)
{
Tnode *W=P->lson;
P->lson=W->rson;
W->rson=P;
P=W;
P->rson->Get_size();
P->Get_size();
}
void Left_turn(Tnode *&P)
{
Tnode *W=P->rson;
P->rson=W->lson;
W->lson=P;
P=W;
P->lson->Get_size();
P->Get_size();
}
void Insert(Tnode *&P,int nv)
{
if (!P) P=New_node(nv);
else
{
if ( nv<P->val )
{
Insert(P->lson,nv);
if ( P->lson->fix < P->fix ) Right_turn(P);
else P->Get_size();
}
else
{
Insert(P->rson,nv);
if ( P->rson->fix < P->fix ) Left_turn(P);
else P->Get_size();
}
}
}
void Up(int x)
{
if (x==fa[x]) return;
Up(fa[x]);
fa[x]=fa[ fa[x] ];
}
void Copy(Tnode *&root,Tnode *P)
{
if (!P) return;
Insert(root,P->val);
Copy(root,P->lson);
Copy(root,P->rson);
}
void Add(int x,int y)
{
Up(x);
Up(y);
x=fa[x];
y=fa[y];
if (x==y) return;
if ( Root[x]->Size < Root[y]->Size )
{
Copy(Root[y],Root[x]);
fa[x]=y;
}
else
{
Copy(Root[x],Root[y]);
fa[y]=x;
}
}
void Delete(Tnode *&P,int nv)
{
if ( nv==P->val )
{
if ( P->lson==NULL )
if ( P->rson==NULL ) P=NULL;
else P=P->rson;
else
if ( P->rson==NULL ) P=P->lson;
else
{
if ( P->lson->fix < P->rson->fix )
{
Right_turn(P);
Delete(P->rson,nv);
}
else
{
Left_turn(P);
Delete(P->lson,nv);
}
P->Get_size();
}
}
else
{
if ( nv<P->val ) Delete(P->lson,nv);
else Delete(P->rson,nv);
P->Get_size();
}
}
int Ask(Tnode *P,int rank)
{
int ls=P->Lsize()+1;
if (rank<ls) return Ask(P->lson,rank);
if (rank>ls) return Ask(P->rson,rank-ls);
return P->val;
}
int main()
{
freopen("c.in","r",stdin);
freopen("c.out","w",stdout);
srand( time(0) );
rand(); rand();
scanf("%d%d",&n,&m);
while ( n || m )
{
Case++;
cur=-1;
for (int i=1; i<=n; i++)
{
Root[i]=NULL;
scanf("%d",&V[i]);
fa[i]=i;
}
for (int i=1; i<=m; i++)
{
use[i]=true;
scanf("%d%d",&u[i],&v[i]);
}
numq=w=0;
sum=0;
scanf("%s",&op);
while (op[0]!='E')
{
w++;
if (op[0]=='D')
{
work[w].id=0;
scanf("%d",&work[w].a);
use[ work[w].a ]=false;
}
if (op[0]=='C')
{
work[w].id=1;
scanf("%d",&work[w].a);
work[w].b=V[ work[w].a ];
scanf("%d",&V[ work[w].a ]);
}
if (op[0]=='Q')
{
work[w].id=2;
scanf("%d%d",&work[w].a,&work[w].b);
numq++;
}
scanf("%s",&op);
}
for (int i=1; i<=n; i++) Insert(Root[i],V[i]);
for (int i=1; i<=m; i++)
if (use[i]) Add(u[i],v[i]);
for (int i=w; i>=1; i--)
{
if (!work[i].id) Add(u[ work[i].a ],v[ work[i].a ]);
if (work[i].id==1)
{
int wa=work[i].a;
Up(wa);
Delete(Root[ fa[wa] ],V[wa]);
Insert(Root[ fa[wa] ],V[wa]=work[i].b);
}
if (work[i].id==2)
{
int wa=work[i].a;
Up(wa);
int k=Root[ fa[wa] ]->Size-work[i].b+1;
if ( k<1 || k>Root[ fa[wa] ]->Size ) continue;
sum+=(long long)Ask(Root[ fa[wa] ],k);
}
}
double ans=(double)sum/(double)numq;
printf("Case %d: %.6lf\n",Case,ans);
scanf("%d%d",&n,&m);
}
return 0;
}