Graph and Queries
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2649 Accepted Submission(s): 600
1) Deletes an edge from the graph.
The format is [D X], where X is an integer from 1 to M, indicating the ID of the edge that you should delete. It is guaranteed that no edge will be deleted more than once.
2) Queries the weight of the vertex with K-th maximum value among all vertexes currently connected with vertex X (including X itself).
The format is [Q X K], where X is an integer from 1 to N, indicating the id of the vertex, and you may assume that K will always fit into a 32-bit signed integer. In case K is illegal, the value for that query will be considered as undefined, and you should return 0 as the answer to that query.
3) Changes the weight of a vertex.
The format is [C X V], where X is an integer from 1 to N, and V is an integer within the range [-106, 106].
The operations end with one single character, E, which indicates that the current case has ended.
For simplicity, you only need to output one real number - the average answer of all queries.
There will be a blank line between two successive cases. A case with N = 0, M = 0 indicates the end of the input file and this case should not be processed by your program.
題意:n個結點,m條邊的無向圖,每個節點有一個整數權值。
3種操作:
D X,刪除id爲X的邊。輸入保證每條邊至多被刪除一次。
Q X k , 計算與結點X聯通的結點中(包括X),第K大的權值。如果不存在,輸出0。
C X V,把結點X的權值改爲V
輸出所有詢問的平均值。
題解:離線操作,我們把操作倒過來,把刪邊操作轉換爲加邊。由於要詢問第K大,所以我們用平衡樹維護一個聯通塊中的點。當我們要合併兩個聯通塊時,將結點數小的平衡樹中的點加入另一個平衡樹,刪除結點數小的平衡樹,這樣的合併稱爲啓發式合併。我們來分析一下複雜度,由於1個點合併以後,它所在的樹的範圍至少增大一倍。所以這個點最多合併logn次,每次合併的複雜度爲logn,所以合併的總複雜度爲O(n*logn*logn)。單次詢問和修改的複雜度爲logn。
代碼如下:
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<map>
#include<string.h>
#include<vector>
#define nn 21000
#define mod 100003
typedef long long LL;
typedef unsigned long long LLU;
const double eps=1e-8;
using namespace std;
int n,m;
int a[nn];
struct node
{
char c;
int x,k;
}ask[nn*30];
int u[nn*3],v[nn*3];
bool use[nn*3];
int fa[nn];
struct node1
{
int val;
int key;
int num;
int sum;
node1* son[2];
};
node1* Tree[nn];
void update(node1* id)
{
if(id==NULL)
return ;
id->sum=id->num;
if(id->son[0]!=NULL)
id->sum+=id->son[0]->sum;
if(id->son[1]!=NULL)
id->sum+=id->son[1]->sum;
}
void Rotate(node1* &id,int d)
{
node1* tem=id->son[d];
id->son[d]=tem->son[d^1];
tem->son[d^1]=id;
update(id);
update(tem);
id=tem;
}
void Insert(node1* &id,int val)
{
if(id==NULL)
{
id=new node1;
id->val=val;
id->key=rand()*rand();
id->num=id->sum=1;
id->son[0]=id->son[1]=NULL;
return ;
}
if(id->val==val)
{
id->num++;
id->sum++;
}
else if(val<id->val)
{
Insert(id->son[0],val);
update(id);
if(id->son[0]->key<id->key)
{
Rotate(id,0);
}
}
else
{
Insert(id->son[1],val);
update(id);
if(id->son[1]->key<id->key)
{
Rotate(id,1);
}
}
}
void Remove(node1* &id,int val)
{
if(id==NULL)
return ;
if(id->val==val)
{
if(id->num==1)
{
if(id->son[0]==NULL)
{
node1* tem=id;
id=id->son[1];
delete tem;
}
else if(id->son[1]==NULL)
{
node1* tem=id;
id=id->son[0];
delete tem;
}
else
{
if(id->son[0]->key<id->son[1]->key)
{
Rotate(id,0);
Remove(id->son[1],val);
}
else
{
Rotate(id,1);
Remove(id->son[0],val);
}
}
}
else
id->num--;
}
else if(id->val>val)
Remove(id->son[0],val);
else
Remove(id->son[1],val);
update(id);
}
int Kth(node1* id,int k)
{
if(id==NULL||k<=0||k>id->sum)
return 0;
int tem=0;
if(id->son[1]!=NULL)
tem+=id->son[1]->sum;
if(tem>=k)
{
return Kth(id->son[1],k);
}
else if(tem+id->num>=k)
{
return id->val;
}
else
return Kth(id->son[0],k-tem-id->num);
}
int findfa(int x)
{
if(fa[x]==x)
return x;
return fa[x]=findfa(fa[x]);
}
void Union(node1* &id,int y)
{
if(id==NULL)
return ;
Union(id->son[0],y);
Union(id->son[1],y);
for(int i=0;i<id->num;i++)
{
Insert(Tree[y],id->val);
}
delete id;
id=NULL;
}
void Clear(node1* &id)
{
if(id==NULL)
return ;
Clear(id->son[0]);
Clear(id->son[1]);
delete id;
id=NULL;
}
int main()
{
int i;
char s[5];
int cas=1;
while(scanf("%d%d",&n,&m)&&(n+m))
{
memset(use,false,sizeof(use));
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
for(i=1;i<=m;i++)
{
scanf("%d%d",&u[i],&v[i]);
}
int la=0;
while(1)
{
scanf("%s",s);
if(s[0]=='E')
break;
la++;
ask[la].c=s[0];
if(s[0]=='D')
{
scanf("%d",&ask[la].x);
use[ask[la].x]=true;
ask[la].k=-1;
}
else
{
scanf("%d%d",&ask[la].x,&ask[la].k);
if(s[0]=='C')
{
int tem=a[ask[la].x];
a[ask[la].x]=ask[la].k;
ask[la].k=tem;
}
}
}
for(i=1;i<=n;i++)
{
fa[i]=i;
Tree[i]=NULL;
Insert(Tree[i],a[i]);
}
for(i=1;i<=m;i++)
{
if(!use[i])
{
int fx=findfa(u[i]);
int fy=findfa(v[i]);
if(fx!=fy)
{
if(Tree[fx]->sum<Tree[fy]->sum)
{
fa[fx]=fy;
Union(Tree[fx],fy);
}
else
{
fa[fy]=fx;
Union(Tree[fy],fx);
}
}
}
}
double ans=0;
int q=0;
for(i=la;i>=1;i--)
{
if(ask[i].c=='D')
{
int fx=findfa(u[ask[i].x]);
int fy=findfa(v[ask[i].x]);
if(fx!=fy)
{
if(Tree[fx]->sum<Tree[fy]->sum)
{
fa[fx]=fy;
Union(Tree[fx],fy);
}
else
{
fa[fy]=fx;
Union(Tree[fy],fx);
}
}
}
else if(ask[i].c=='Q')
{
q++;
ans+=Kth(Tree[findfa(ask[i].x)],ask[i].k);
}
else
{
int ix=findfa(ask[i].x);
Remove(Tree[ix],a[ask[i].x]);
a[ask[i].x]=ask[i].k;
Insert(Tree[ix],ask[i].k);
}
}
for(i=1;i<=n;i++)
{
Clear(Tree[i]);
}
printf("Case %d: %.6lf\n",cas++,double(ans)/q);
}
return 0;
}