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

来源:互联网 发布:航空票务网站源码 编辑:程序博客网 时间:2024/06/05 16:49

传送门:[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[N],Num[N];int s[N],tot1,tot2,size[N],val[N],fa[N],f[N],root[N],n,Siz[N],flag[N],cnt[N],ch[N][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的子树调整为goalvoid 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;}
0 0