• [并查集][线段树]luogu P3273 [SCOI2011]棘手的操作


    题面

    https://www.luogu.com.cn/problem/P3273

    大意是给n个初始独立的点,有7种操作:

    1、在两个点之间连一条无向边

    2、给一个点加上一个权值

    3、给一个点所在的连通块中的所有点加上一个权值

    4、给所有点加上一个权值

    5、查询一个点的权值

    6、查询一个点所在的连通块中的所有点的最大权值

    7、查询所有点的最大权值

    分析

    查询和修改操作都很像线段树,但是由于连边操作,序号是断裂的

    考虑离线用链表来维护点的线段树序号,当连接两个连通块时,将两个连通块的序号序列用链表相连,最后按照链表上的顺序给点编号

    并查集维护连通块,这样重标号的序列每次合并后都是一个连续的区间了

    再将所有操作做一遍,连边操作就将区间端点扩张一下即可,剩下就是线段树基操了

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define lson (x<<1)
    #define rson ((x<<1)+1)
    using namespace std;
    const int Inf=2147483647;
    const int N=3e5+10;
    struct Task {
        int tp,x,y;
    }p[N];
    int n,m;
    int f[N],t[4*N],lz[4*N],ref[N],bac[N],cnt,l[N],r[N],pre[N],nex[N],st[N],ed[N],a[N];
    
    int Get_F(int x) {return f[x]==x?x:f[x]=Get_F(f[x]);}
    
    void Pushdown(int x,int l,int r) {
        if (!lz[x]) return;
        int mid=l+r>>1;
        t[lson]+=lz[x];lz[lson]+=lz[x];
        t[rson]+=lz[x];lz[rson]+=lz[x];
        lz[x]=0;
    }
    
    void Change(int x,int l,int r,int ll,int rr,int k) {
        if (ll<=l&&r<=rr) {t[x]+=k;lz[x]+=k;return;}
        int mid=l+r>>1;
        Pushdown(x,l,r);
        if (ll<=mid) Change(lson,l,mid,ll,rr,k);
        if (mid<rr) Change(rson,mid+1,r,ll,rr,k);
        t[x]=max(t[lson],t[rson]);
    }
    
    int Query(int x,int l,int r,int ll,int rr) {
        if (ll<=l&&r<=rr) return t[x];
        int mid=l+r>>1,ans=-Inf;
        Pushdown(x,l,r);
        if (ll<=mid) ans=Query(lson,l,mid,ll,rr);
        if (mid<rr) ans=max(ans,Query(rson,mid+1,r,ll,rr));
        return ans;
    }
    
    int main() {
        scanf("%d",&n);
        for (int i=1;i<=n;i++) scanf("%d",&a[i]),f[i]=st[i]=ed[i]=i;
        scanf("%d",&m);
        for (int i=1,x,y;i<=m;i++) {
            char s[4];
            scanf("%s",s);
            if (s[0]=='U') {
                scanf("%d%d",&x,&y);
                x=Get_F(x);y=Get_F(y);
                if (x!=y) f[y]=x,pre[st[y]]=ed[x],nex[ed[x]]=st[y],ed[x]=ed[y];
                p[i]=(Task){0,x,y};
            }
            if (s[0]=='A') {
                scanf("%d",&x);
                if (s[1]<'3') scanf("%d",&y);
                p[i]=(Task){s[1]-'0',x,y};
            }
            if (s[0]=='F') {
                if (s[1]<'3') scanf("%d",&x);
                p[i]=(Task){s[1]-'0'+3,x,y};
            }
        }
        for (int i=1;i<=n;f[i]=i,i++)
            if (!pre[i]) for (int j=i;j;j=nex[j]) bac[l[j]=r[j]=ref[j]=++cnt]=j,Change(1,1,n,ref[j],ref[j],a[j]);
        for (int i=1,x,y;i<=m;i++)  {
            x=p[i].x;y=p[i].y;
            if (!p[i].tp) {
                x=Get_F(x);y=Get_F(y);
                if (x!=y) f[y]=x,l[x]=min(l[x],l[y]),r[x]=max(r[x],r[y]);
            }
            if (p[i].tp==1) Change(1,1,n,ref[x],ref[x],y);
            if (p[i].tp==2) x=Get_F(x),Change(1,1,n,l[x],r[x],y);
            if (p[i].tp==3) Change(1,1,n,1,n,x);
            if (p[i].tp==4) printf("%d
    ",Query(1,1,n,ref[x],ref[x]));
            if (p[i].tp==5) x=Get_F(x),printf("%d
    ",Query(1,1,n,l[x],r[x]));
            if (p[i].tp==6) printf("%d
    ",t[1]);
        }
    }
    View Code
    在日渐沉没的世界里,我发现了你。
  • 相关阅读:
    Visual Studio Code使用NVM指定的节点版本
    webpackd学习的意义
    scss--函数 (Functions)--unit
    scss--函数 (Functions)--unitless
    JS中的事件绑定,事件捕获,事件冒泡以及事件委托,事件参数(event.target,e.srcElement,event.currentTarget,),兼容IE
    移动端rem
    单例模式
    代理模式
    装饰者模式
    策略模式
  • 原文地址:https://www.cnblogs.com/mastervan/p/14553201.html
Copyright © 2020-2023  润新知