您的位置:首页 > 产品设计 > UI/UE

Hdu 3726 Graph and Queries(删边,查询第k大,修改点值)

2016-08-25 14:20 393 查看
传送门:[(Hdu]http://acm.split.hdu.edu.cn/showproblem.php?pid=3726](Hdu 3726 Graph and Queries)

题意:给你n个点,m条边,有下面三种操作

1:D X :删掉第X条边。

2:Q X K :查询和X相连的点中第K大的点的值

3:C X V :将点X的权值修改为V

思路:逆向处理,利用并查集+Splay

按值建立Splay,修改点值,先找到这个点,让这个点作为根,删除根

删除边,判断两个点的并查集是否相同,暴力合并(每个点最多被合并logn次),所以合并时间复杂度为logn^2

#include<bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
const int N=6e4+10;
const int M=6e4+10;
struct query{
int op,x,k;
}Q[M*10];
struct Edge{
int from,to;
}E[M];
vector<int>G
,Num
;
int s
,tot1,tot2,size
,val
,fa
,f
,root
,n,Siz
,flag
,cnt
,ch
[2];
int case1=1;

void Newnode(int &now,int father,int k){
if(tot2)    now=s[tot2--];
else    now=++tot1;
val[now]=k,fa[now]=father,size[now]=1,cnt[now]=1;
ch[now][0]=ch[now][1]=0;
}

void erase(int x){
if(!x)  return ;
s[++tot2]=x;
erase(ch[x][0]),erase(ch[x][1]);
}

void pushup(int x){
size[x]=size[ ch[x][0] ]+size[ ch[x][1] ]+cnt[x];
}

//旋转,kind为1为右旋,kind为0为左旋
void Rotate(int x,int kind){
int y=fa[x];
ch[y][!kind]=ch[x][kind];
fa[ch[x][kind]]=y;
//如果父节点不是根结点,则要和父节点的父节点连接起来
if(fa[y])
ch[ fa[y] ][ch[fa[y]][1]==y]=x;
fa[x]=fa[y];
ch[x][kind]=y;
fa[y]=x;
pushup(y);
}

//Splay调整,将根为now的子树调整为goal
void Splay(int now,int goal,int Belong){
while(fa[now]!=goal){
if(fa[ fa[now] ]==goal)
Rotate(now,ch[ fa[now] ][0]==now);
else{
int pre=fa[now],kind=ch[ fa[pre] ][0]==pre; //左儿子为1,右儿子为0
if(ch[pre][kind]==now){ //两个方向不同
Rotate(now,!kind);
Rotate(now,kind);
}
else{   //两个方向相同
Rotate(pre,kind);
Rotate(now,kind);
}
}
}
if(goal==0) root[Belong]=now;
pushup(now);
}

int get_kth(int x,int k){
int num1=size[ch[x][0]];
int num2=size[ch[x][0]]+cnt[x];
if(num1<k&&num2>=k)
return x;
if(num1>=k)   return get_kth(ch[x][0],k);
return get_kth(ch[x][1],k-num2);
}

int find(int x){
if(x==f[x])
return f[x];
f[x]=find(f[x]);
return f[x];
}
char str[3];

void init(){
tot1=tot2=0;
for(int i=1;i<=n;i++){
Newnode(root[i],0,-INF);
Newnode(ch[root[i]][1],root[i],INF);
Newnode(ch[ch[root[i]][1]][0],ch[root[i]][1],Num[i].back());
pushup(ch[root[i]][1]),pushup(root[i]);
}
}

void Insert(int k,int Belong){
int now=root[Belong];
while(ch[now][val[now]<k]){
if(val[now]==k){
Splay(now,0,Belong),cnt[root[Belong]]++;
pushup(root[Belong]);
return ;
}
now=ch[now][val[now]<k];
}
Newnode(ch[now][k>val[now]],now,k);
//将新插入的结点更新至根结点
Splay(ch[now][k>val[now]],0,Belong);
return ;
}

int getmax(int x){
while(ch[x][1])
x=ch[x][1];
return x;
}

void remove(int Belong){
int m=getmax(ch[root[Belong]][0]);
Splay(m,root[Belong],Belong);
ch[m][1]=ch[root[Belong]][1];
fa[ch[root[Belong]][1]]=m;
root[Belong]=m;
fa[root[Belong]]=0;
pushup(root[Belong]);
}

void Delete(int k,int Belong){
int now=root[Belong];
while(ch[now][val[now]<k]){
if(val[now]==k){
Splay(now,0,Belong);
if(cnt[root[Belong]]>1)
cnt[root[Belong]]--;
else{
s[++tot2]=root[Belong];
remove(Belong);
}
pushup(root[Belong]);
return ;
}
now=ch[now][val[now]<k];
}
if(val[now]==k){
Splay(now,0,Belong);
if(cnt[root[Belong]]>1)
cnt[root[Belong]]--;
else{
s[++tot2]=root[Belong];
remove(Belong);
}
pushup(root[Belong]);
return ;
}
}

void Union(int x,int y){
erase(root[y]),root[y]=0,fa[root[y]]=0;
for(int i=0;i<G[y].size();i++){
G[x].push_back(G[y][i]);
Insert(Num[ G[y][i] ].back(),x);
}
G[y].clear();
}

void merge(int from,int to){
int x=find(from),y=find(to);
if(x==y)
return ;
if(Siz[x]>Siz[y])
Union(x,y),f[y]=x,Siz[x]+=Siz[y];
else
Union(y,x),f[x]=y,Siz[y]+=Siz[x];
}

void travel(int x){
if(x==0)
return ;
travel(ch[x][0]);
printf("%d ",val[x]);
travel(ch[x][1]);
}

void change(int x,int k){
int xx=find(x);
Num[x].pop_back();
Delete(k,xx);
Insert(Num[x].back(),xx);   //更新为这个
}

int main(){
int m,x;
while(scanf("%d%d",&n,&m)!=EOF){
if(n==0&&m==0)
break;
memset(flag,0,sizeof(flag));
for(int i=1;i<=n;i++)   f[i]=i,Siz[i]=1,G[i].clear(),Num[i].clear();
for(int i=1;i<=n;i++)   scanf("%d",&x),G[i].push_back(i),Num[i].push_back(x);
for(int i=1;i<=m;i++)
scanf("%d%d",&E[i].from,&E[i].to);
int cnt=0;
for(int i=1;;i++){
scanf("%s",str);
if(str[0]=='E'){
cnt=i-1;
break;
}
if(str[0]=='D')
Q[i].op=1,scanf("%d",&Q[i].x),flag[Q[i].x]=1;
else if(str[0]=='Q')
Q[i].op=2,scanf("%d%d",&Q[i].x,&Q[i].k);
else
Q[i].op=3,scanf("%d%d",&Q[i].x,&Q[i].k),Num[Q[i].x].push_back(Q[i].k);
}
init();
for(int i=1;i<=m;i++)
if(flag[i]==0)
merge(E[i].from,E[i].to);
double ans=0;
int Count=0;
for(int i=cnt;i>=1;i--){
if(Q[i].op==1)
merge(E[Q[i].x].from,E[Q[i].x].to);
else if(Q[i].op==2){
Count++;
int x=find(Q[i].x);
if(size[root[x]]-Q[i].k>=2&&Q[i].k>=1)
ans+=val[get_kth(root[x],size[root[x]]-Q[i].k)];
}
else
change(Q[i].x,Q[i].k);
}
printf("Case %d: %.6f\n",case1++,ans/Count);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: