BZOJ 2333 [SCOI2011]棘手的操作

本文介绍了一道名为[BZOJ2333][SCOI2011]棘手的操作的问题解决方法,通过离线处理和线段树维护连通块的最大权值,实现对连通块的操作及查询。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

BZOJ 2333 [SCOI2011]棘手的操作

线段树,离线,图论

题意

给你N个点,每点开始时是独立的,有点权。
设计数据结构支持:

  • 加边,将点x,点y连通
  • 修改单点权值、修改整体权值、修改某一点所在连通块的权值
  • 查询单点权值、查询整体最大权值、查询某一点所在连通块的最大权值

思路

%%%

因为两个连通块合并后就不会被拆开,所以考虑离线。处理出最后的树,进行dfs序,对每个点重新标号。这样就把连通块变成了区间操作,线段树维护最大值即可。

关于重新标号:用三个数组维护,fa表示某个点所在连通块得第一个节点;ne表示某个点的后继节点(独立点或某块的最后一点为0);la只对某一连通块的第一个点有效,表示该连通块的最后一个点。在联通块内用ne数组遍历标号。

预处理dfs序标号到ha数组。查询时,重做一遍,查询某个点的连通块相当于查询query(ha[getfa(x)], ha[la[getfa(x)]], 1, n, 1))

代码

#include <bits/stdc++.h>
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define M(a,b) memset(a,b,sizeof(a))
using namespace std;
const int MAXN=300007;
const int oo=0x3f3f3f3f;

int haval[MAXN], val[MAXN], ha[MAXN];

//询问
struct Query
{
    int op;int x, y;
    Query() { op=x=y=0; }
    inline void read()
    {
        char tmp[5];scanf("%s", tmp);
        if(tmp[0]=='U') scanf("%d%d", &x, &y), op=1;
        else if(tmp[0]=='A')
        {
            if(tmp[1]=='1') scanf("%d%d", &x, &y), op=2;//单点修改
            if(tmp[1]=='2') scanf("%d%d", &x, &y), op=3;//联通块修改
            if(tmp[1]=='3') scanf("%d", &x), op=4;//整体修改
        }
        else if(tmp[0]=='F')
        {
            if(tmp[1]=='1') scanf("%d", &x), op=5;//单点查询
            if(tmp[1]=='2') scanf("%d", &x), op=6;//联通块查询
            if(tmp[1]=='3') op=7;//整体查询
        }
    }
}q[MAXN];

//并查集
int fa[MAXN], ne[MAXN], la[MAXN];
inline void init(int n) { for(int i=1;i<=n;i++) fa[i]=la[i]=i;M(ne, 0); }
int getfa(int x) { return fa[x]==x ? x : fa[x]=getfa(fa[x]); }

//线段树
struct STREE
{
    int maxval, lazy;
}stree[MAXN<<2];
inline void pushup(int rt)
{
    stree[rt].maxval=max(stree[rt<<1].maxval, stree[rt<<1|1].maxval);
}
inline void pushdown(int rt)
{
    if(stree[rt].lazy!=0)
    {
        stree[rt<<1].maxval+=stree[rt].lazy;
        stree[rt<<1|1].maxval+=stree[rt].lazy;
        stree[rt<<1].lazy+=stree[rt].lazy;
        stree[rt<<1|1].lazy+=stree[rt].lazy;
        stree[rt].lazy=0;
    }
}
void build(int l, int r, int rt)
{
    stree[rt].lazy=0;
    if(l==r) { stree[rt].maxval=haval[l]; return; }
    int mid=(l+r)>>1;
    build(lson), build(rson);
    pushup(rt);
}
void update(int L, int R, int v, int l, int r, int rt)
{
    if(L<=l&&r<=R)
    {
        stree[rt].maxval+=v;
        stree[rt].lazy+=v;
        return;
    }
    pushdown(rt);
    int mid=(l+r)>>1;
    if(L<=mid) update(L, R, v, lson);
    if(mid<R) update(L, R, v, rson);
    pushup(rt);
}
int query(int L, int R, int l, int r, int rt)
{
    if(L<=l&&r<=R) return stree[rt].maxval;
    pushdown(rt);
    int mid=(l+r)>>1, res=-oo;
    if(L<=mid) res=max(res, query(L, R, lson));
    if(mid<R) res=max(res, query(L, R, rson));
    return res;
}

int main()
{
    int n;
    while(scanf("%d", &n)==1)
    {
        init(n);
        for(int i=1;i<=n;i++) scanf("%d", &val[i]);
        int m;scanf("%d", &m);
        for(int i=1;i<=m;i++)
        {
            q[i].read();
            if(q[i].op==1)
            {
                int x=q[i].x, y=q[i].y;
                int fx=getfa(x), fy=getfa(y);
                if(fx!=fy)
                {
                    fa[fy]=fx;ne[la[fx]]=fy;la[fx]=la[fy];
                }
            }
        }
        int cnt=0;
        for(int i=1;i<=n;i++)
            if(getfa(i)==i)
                for(int j=i;j!=0;j=ne[j])
                {
                    ha[j]=++cnt;haval[cnt]=val[j];
                }

        build(1, n, 1), init(n);

        for(int i=1;i<=m;i++)
        {
            if(q[i].op==1)
            {
                int x=q[i].x, y=q[i].y;
                int fx=getfa(x), fy=getfa(y);
                if(fx!=fy)
                {
                    fa[fy]=fx;ne[la[fx]]=fy;la[fx]=la[fy];
                }
            }
            else if(q[i].op==2)
            {
                int x=q[i].x, v=q[i].y;
                update(ha[x], ha[x], v, 1, n, 1);
            }
            else if(q[i].op==3)
            {
                int x=q[i].x, v=q[i].y;
                int fx=getfa(x);
                update(ha[fx], ha[la[fx]], v, 1, n, 1);
            }
            else if(q[i].op==4)
            {
                int v=q[i].x;
                update(1, n, v, 1, n, 1);
            }
            else if(q[i].op==5)
            {
                int x=q[i].x;
                printf("%d\n", query(ha[x], ha[x], 1, n, 1));
            }
            else if(q[i].op==6)
            {
                int x=q[i].x;
                int fx=getfa(x);
                printf("%d\n", query(ha[fx], ha[la[fx]], 1, n, 1));
            }
            else if(q[i].op==7)
            {
                printf("%d\n", query(1, n, 1, n, 1));
            }
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值