[UER #1C]Dzy Loves Graph

题目大意

有n个结点,初始没有边。m个操作,操作类型有三:
1、a与b之间连一条长度为i的边(i为操作编号)
2、删除比边权最大的k条边。
3、撤销刚刚执行的操作,保证撤销的不是撤销操作。
每次操作后输出最小生成树所有边权和。

可持久化并查集

有许多版本,于是我们发现版本之间形成树的结构,为什么?
加入的边越来越大,因此删除操作相当于跳到k级祖先,每次添加操作就在下面加一个儿子,所以是树的结构。
撤销也很容易,直接看i-2所在版本即可。
我们维护并查集,如果加入的边的两端点在同一集合,由于是最小生成树,而新加入这边一定边权最大,所以不需要更新答案。
于是我们可以维护可持久化并查集。
至于跳到祖先,可以每加入一个点就处理一下倍增数组。
程序其实是非AC代码QAQ

#include<cstdio>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=300000+10,maxm=500000+10;
int fa[maxm][25],last[maxm],data[maxm],cnt[maxm],wz[maxm];
int left[maxm*6],right[maxm*6],key[maxm*6],root[maxm];
int i,j,k,l,t,n,m,tot,top,now;
char ch;
int read(){
    int x=0,f=1;
    char ch=getchar();
    while (ch<'0'||ch>'9'){
        if (ch=='-') f=-1;
        ch=getchar();
    }
    while (ch>='0'&&ch<='9'){
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}
char get(){
    char ch=getchar();
    while (ch!='A'&&ch!='D'&&ch!='R') ch=getchar();
    return ch;
}
int newnode(int x){
    top++;
    left[top]=left[x];
    right[top]=right[x];
    key[top]=key[x];
    return top;
}
void change(int &x,int l,int r,int a,int b){
    x=newnode(x);
    if (l==r){
        key[x]=b;
        return;
    }
    int mid=(l+r)/2;
    if (a<=mid) change(left[x],l,mid,a,b);else change(right[x],mid+1,r,a,b);
}
int query(int x,int l,int r,int a){
    if (l==r) return key[x];
    int mid=(l+r)/2;
    if (a<=mid) return query(left[x],l,mid,a);else return query(right[x],mid+1,r,a);
}
int getfa(int id,int x){
    int f=query(root[id],1,n,x);
    if (f==0) return x;
    f=getfa(id,f);
    change(root[id],1,n,x,f);
    return f;
}
int getfather(int x,int y){
    int j=floor(log(m)/log(2));
    while (j>=0){
        if ((1<<j)<=y){
            y-=(1<<j);
            x=fa[x][j];
        }
        j--;
    }
    return x;
}
int main(){
    freopen("dzy.in","r",stdin);
    n=read();m=read();
    fo(i,1,m){
        ch=get();
        if (ch=='A'){
            ++tot;
            fa[tot][0]=now;
            data[tot]=data[now];
            cnt[tot]=cnt[now];
            root[tot]=root[now];
            now=tot;
            fo(j,1,floor(log(m)/log(2))) fa[tot][j]=fa[fa[tot][j-1]][j-1];
            j=read();k=read();
            j=getfa(tot,j);
            k=getfa(tot,k);
            if (j!=k){
                change(root[tot],1,n,j,k);
                data[tot]+=i;
                cnt[tot]++;
            }
        }
        else if (ch=='D'){
            k=read();
            now=getfather(now,k);
        }
        else if (ch=='R') now=wz[i-2];
        if (cnt[now]==n-1) printf("%d\n",data[now]);else printf("0\n");
        wz[i]=now;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值