#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e4+10;
const int maxm = 6e5+10;
const int maxc = 5e5+10;
struct Node{
Node* ch[2];
int value;
int rank_value;
int s;
Node(int value):value(value){
ch[0] = ch[1] = NULL;
rank_value = rand();
s = 1;
}
int cmp(int x){
if(x == value) return -1;
return x<value?0:1;
}
void maintain(){
s = 1;
if(ch[0] != NULL) s+=ch[0]->s;
if(ch[1] != NULL) s+=ch[1]->s;
}
};
void rotate(Node* &rt, int d){
Node* k = rt->ch[d^1];
rt->ch[d^1] = k->ch[d];
k->ch[d] = rt;
rt->maintain();
k->maintain();
rt = k;
}
void insert(Node* &rt, int value){
if(rt == NULL) rt = new Node(value);
else{
int d = rt->value<value?1:0;
insert(rt->ch[d], value);
if(rt->ch[d]->rank_value>rt->rank_value){
rotate(rt, d^1);
}
}
rt->maintain();
}
void remove(Node* &rt, int value){
int d = rt->cmp(value);
Node * temp = rt;
if(d == -1){
if(rt->ch[0] == NULL) rt = rt->ch[1], delete temp;
else if(rt->ch[1] == NULL) rt = rt->ch[0], delete temp;
else{
int d2 = (rt->ch[0]->rank_value<rt->ch[1]->rank_value)?1:0;
rotate(rt, d2);
remove(rt->ch[d2], value);
}
}
else{
remove(rt->ch[d], value);
}
if(rt != NULL) rt->maintain();
}
struct Command{
char type;
int x, p;
}command[maxc];
Node* root[maxn];
int n, m, weight[maxn], from[maxm], to[maxm];
int fa[maxn];
int findset(int x){
return fa[x] == x? x:fa[x] = findset(fa[x]);
}
int kth(Node* rt, int k){
if(k<=0||rt->s<k||rt == NULL) return 0;
int k1;
if(rt->ch[1]!=NULL){
k1 = rt->ch[1]->s;
}
else k1 = 0;
if(k1+1 == k) return rt->value;
else if(k<=k1) return kth(rt->ch[1], k);
else return kth(rt->ch[0], k-k1-1);
}
void mergeto(Node* &sc, Node* &dst){
if(sc->ch[0]!=NULL) mergeto(sc->ch[0], dst);
if(sc->ch[1]!=NULL) mergeto(sc->ch[1], dst);
insert(dst, sc->value);
delete sc;
sc = NULL;
}
void init_tree(Node* &rt){
if(rt->ch[0] != NULL) init_tree(rt->ch[0]);
if(rt->ch[1] != NULL) init_tree(rt->ch[1]);
delete rt;
rt = NULL;
}
void add_edge(int edge_index){
int u = from[edge_index];
int v = to[edge_index];
u = findset(u);
v = findset(v);
if(u != v){
if(root[u]->s<root[v]->s){
fa[u] = v;
mergeto(root[u], root[v]);
}
else{
fa[v] = u;
mergeto(root[v], root[u]);
}
}
}
void change(int x, int value){
int u = findset(x);
remove(root[u], weight[x]);
insert(root[u], value);
weight[x] = value;
}
int query_cnt;
long long query_tot;
void query(int x, int k){
query_cnt++;
query_tot += kth(root[findset(x)], k);
}
bool removed[maxm];
int main()
{
int kase = 0;
while(scanf("%d %d", &n, &m) == 2&&n){
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 c = 0;
memset(removed, 0, sizeof(removed));
while(true){
char type;
int x, p;
getchar();
scanf("%c", &type);
if(type == 'E') break;
else if(type == 'C') {
scanf("%d%d", &x, &p);
int temp = p;
p = weight[x];
weight[x] = temp;
}
else if(type == 'D'){
scanf("%d", &x);
removed[x] = true;
}
else if(type == 'Q'){
scanf("%d%d", &x, &p);
}
command[c++] = Command{type, x, p};
}
for(int i=1; i<=n; i++){
fa[i] = i;
if(root[i] != NULL) init_tree(root[i]);
root[i] = new Node(weight[i]);
}
for(int i=1; i<=m; i++){
if(!removed[i]) add_edge(i);
}
query_cnt = query_tot = 0;
for(int i=c-1; i>=0; i--){
if(command[i].type == 'C') change(command[i].x, command[i].p);
if(command[i].type == 'Q') query(command[i].x, command[i].p);
if(command[i].type == 'D') add_edge(command[i].x);
}
printf("Case %d: %.6lf\n", ++kase, query_tot*1.0/query_cnt);
}
return 0;
}