zoukankan      html  css  js  c++  java
  • bzoj2333 [SCOI2011]棘手的操作

    2333: [SCOI2011]棘手的操作

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 2881  Solved: 1117
    [Submit][Status][Discuss]

    Description

    N个节点,标号从1N,这N个节点一开始相互不连通。第i个节点的初始权值为a[i],接下来有如下一些操作:

    U x y: 加一条边,连接第x个节点和第y个节点

    A1 x v: 将第x个节点的权值增加v

    A2 x v: 将第x个节点所在的连通块的所有节点的权值都增加v

    A3 v: 将所有节点的权值都增加v

    F1 x: 输出第x个节点当前的权值

    F2 x: 输出第x个节点所在的连通块中,权值最大的节点的权值

    F3: 输出所有节点中,权值最大的节点的权值

     

    Input

     

    输入的第一行是一个整数N,代表节点个数。

    接下来一行输入N个整数,a[1], a[2], …, a[N],代表N个节点的初始权值。

    再下一行输入一个整数Q,代表接下来的操作数。

    最后输入Q行,每行的格式如题目描述所示。

     

    Output

    对于操作F1, F2, F3,输出对应的结果,每个结果占一行。

     

    Sample Input

    3

    0 0 0

    8

    A1 3 -20

    A1 2 20

    U 1 3

    A2 1 10

    F1 3

    F2 3

    A3 -10

    F3

    Sample Output


    -10

    10

    10

    HINT



     对于30%的数据,保证 N<=100,Q<=10000


    对于80%的数据,保证 N<=100000,Q<=100000


    对于100%的数据,保证 N<=300000,Q<=300000


    对于所有的数据,保证输入合法,并且 -1000<=v, a[1], a[2], …, a[N]<=1000

    Source

    分析:挺好的一道题.
            我一开始的想法是将点和连通块分开处理,最后合并询问就可以了.但是这样会出现一个问题:修改操作互相有影响,有时候修改了一个点可能还要修改连通块,统计点的答案可能还要统计连通块的答案等等,我写了一份这样的代码只能得10分QAQ
            正确解法是利用链表+并查集+线段树.我们要做的事情实际上就是让需要修改查询的点的编号连续,也就是在线段树上能够一次修改完一个区间内所有的点.链表正好能够实现重编号的功能.并查集则是用来维护连通块的.
            因为题目只涉及到加边操作,不会破坏图的结构,所以可以先把“U”操作给单独提出来做,对每一个连通块进行重编号.仅仅只是预先编号。然后将并查集和链表清空.在具体操作中动态加边.这样就能使得操作的点的序号在一个区间内是连续的了.接着就是正常的线段树操作了.在A3操作的时候有一个技巧:用一个变量sum记录加了多少,最后输出的时候加上sum就可以了.
            易错点:建树和询问的重编号数组容易弄反,nextt数组是对于每一个连通块的最后一个元素而言的.
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int maxn = 300010,inf = 0x7ffffff;
    int n,a[maxn],tag[maxn << 2],maxx[maxn << 2],st[maxn],ed[maxn],pos[maxn],id[maxn],q;
    int fa[maxn],nextt[maxn],tot,sum;
    
    struct node
    {
        int id,x,y;
    } e[maxn];
    
    int find(int x)
    {
        if (x == fa[x])
            return x;
        return fa[x] = find(fa[x]);
    }
    
    void pushup(int o)
    {
        maxx[o] = max(maxx[o * 2],maxx[o * 2 + 1]);
    }
    
    void pushdown(int o)
    {
        if (tag[o])
        {
            tag[o * 2] += tag[o];
            tag[o * 2 + 1] += tag[o];
            maxx[o * 2] += tag[o];
            maxx[o * 2 + 1] += tag[o];
            tag[o] = 0;
        }
    }
    
    void build(int o,int l,int r)
    {
        if (l == r)
        {
            maxx[o] = a[pos[l]];
            return;
        }
        int mid = (l + r) >> 1;
        build(o * 2,l,mid);
        build(o * 2 + 1,mid + 1,r);
        pushup(o);
    }
    
    void update(int o,int l,int r,int x,int y,int v)
    {
        if (x <= l && r <= y)
        {
            tag[o] += v;
            maxx[o] += v;
            return;
        }
        pushdown(o);
        int mid = (l + r) >> 1;
        if (x <= mid)
            update(o * 2,l,mid,x,y,v);
        if (y > mid)
            update(o * 2 + 1,mid + 1,r,x,y,v);
        pushup(o);
    }
    
    int query(int o,int l,int r,int x,int y)
    {
        if (x <= l && r <= y)
            return maxx[o];
        int mid = (l + r) >> 1,res = -1e9;
        pushdown(o);
        if (x <= mid)
            res = max(res,query(o * 2,l,mid,x,y));
        if (y > mid)
            res = max(res,query(o * 2 + 1,mid + 1,r,x,y));
        return res;
    }
    
    int main()
    {
        scanf("%d",&n);
        for (int i = 1; i <= n; i++)
            fa[i] = i,ed[i] = i;
        for (int i = 1; i <= n; i++)
            scanf("%d",&a[i]);
        scanf("%d",&q);
        for (int i = 1; i <= q; i++)
        {
            char ch[5];
            int x,y;
            scanf("%s",ch);
            if (ch[0] == 'A' && ch[1] == '1')
            {
                e[i].id = 1;
                scanf("%d%d",&x,&y);
                e[i].x = x;
                e[i].y = y;
            }
            else if (ch[0] == 'A' && ch[1] == '2')
            {
                e[i].id = 2;
                scanf("%d%d",&x,&y);
                e[i].x = x;
                e[i].y = y;
            }
            else if (ch[0] == 'A' && ch[1] == '3')
            {
                e[i].id = 3;
                scanf("%d",&x);
                e[i].x = x;
            }
            else if (ch[0] == 'F' && ch[1] == '1')
            {
                e[i].id = 4;
                scanf("%d",&x);
                e[i].x = x;
            }
            else if (ch[0] == 'F' && ch[1] == '2')
            {
                e[i].id = 5;
                scanf("%d",&x);
                e[i].x = x;
            }
            else if (ch[0] == 'F' && ch[1] == '3')
                e[i].id = 6;
            else
            {
                e[i].id = 7;
                scanf("%d%d",&x,&y);
                e[i].x = x;
                e[i].y = y;
            }
        }
        for (int i = 1; i <= q; i++)
        {
            if (e[i].id == 7)
            {
                int fx = find(e[i].x),fy = find(e[i].y);
                nextt[ed[fx]] = fy;
                ed[fx] = ed[fy];
                fa[fy] = fx;
            }
        }
        for (int i = 1; i <= n; i++)
        {
            if (i == find(i))
            {
                int j = i;
                while (j != ed[i])
                {
                    pos[++tot] = j;
                    id[j] = tot;
                    j = nextt[j];
                }
                pos[++tot] = j;
                id[j] = tot;
            }
        }
        build(1,1,n);
        for (int i = 1; i <= n; i++)
            fa[i] = i,ed[i] = i;
        for (int i = 1; i <= q; i++)
        {
            int x = e[i].x,y = e[i].y;
            if (e[i].id == 1)
                update(1,1,n,id[x],id[x],y);
            if (e[i].id == 2)
                update(1,1,n,id[find(x)],id[ed[find(x)]],y);
            if (e[i].id == 3)
                sum += x;
            if (e[i].id == 4)
                printf("%d
    ",query(1,1,n,id[x],id[x]) + sum);
            if (e[i].id == 5)
                printf("%d
    ",query(1,1,n,id[find(x)],id[ed[find(x)]]) + sum);
            if (e[i].id == 6)
                printf("%d
    ",maxx[1] + sum);
            if (e[i].id == 7)
            {
                int fx = find(x),fy = find(y);
                nextt[ed[fx]] = fy;
                ed[fx] = ed[fy];
                fa[fy] = fx;
            }
        }
    
        return 0;
    }

    我一开始的错解:

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    //单点修改,区间修改,单点查询,区间查询
    const int maxn = 300010;
    int n,a[maxn],fa[maxn],maxx[maxn << 2],tag[maxn << 2],maxx2[maxn << 2],tag2[maxn << 2],q,sum[maxn << 2],L[maxn << 2],R[maxn << 2]; //sum主要看每个连通块加了多少次
    int tag3[maxn << 2],all;
    
    void pushup(int o)
    {
        maxx[o] = max(maxx[o * 2],maxx[o * 2 + 1]);
        maxx2[o] = max(maxx2[o * 2],maxx2[o * 2 + 1]);
        sum[o] = sum[o * 2] + sum[o * 2 + 1];
    }
    
    void build(int o,int l,int r)
    {
        L[o] = l,R[o] = r;
        if (l == r)
        {
            maxx[o] = maxx2[o] = a[l];
            return;
        }
        int mid = (l + r) >> 1;
        build(o * 2,l,mid);
        build(o * 2 + 1,mid + 1,r);
        pushup(o);
    }
    
    int find(int x)
    {
        if (x == fa[x])
            return x;
        return fa[x] = find(fa[x]);
    }
    
    void update1(int o,int l,int r,int x,int y)
    {
        if (l == r)
        {
            maxx[o] += y;
            return;
        }
        int mid = (l + r) >> 1;
        if (x <= mid)
            update1(o * 2,l,mid,x,y);
        else
            update1(o * 2 + 1,mid + 1,r,x,y);
        pushup(o);
    }
    
    void update2(int o,int l,int r,int x,int y)
    {
        if (l == r)
        {
            sum[o] += y;
            maxx2[o] += y;
            return;
        }
        int mid = (l + r) >> 1;
        if (x <= mid)
            update2(o * 2,l,mid,x,y);
        else
            update2(o * 2 + 1,mid + 1,r,x,y);
        pushup(o);
    }
    
    void update3(int o,int l,int r,int x,int y)
    {
        if (l == r)
        {
            maxx2[o] += y;
            return;
        }
        int mid = (l + r) >> 1;
        if (x <= mid)
            update3(o * 2,l,mid,x,y);
        else
            update3(o * 2 + 1,mid + 1,r,x,y);
        pushup(o);
    }
    
    void update4(int o,int l,int r,int x,int y)
    {
        if (l == r)
        {
            maxx2[o] = y;
            return;
        }
        int mid = (l + r) >> 1;
        if (x <= mid)
        update4(o * 2,l,mid,x,y);
        else
        update4(o * 2 + 1,mid + 1,r,x,y);
        pushup(o);
    }
    
    int query1(int o,int l,int r,int x)
    {
        if (l == r)
            return maxx[o];
        int mid = (l + r) >> 1;
        if (x <= mid)
            return query1(o * 2,l,mid,x);
        else
            return query1(o * 2 + 1,mid + 1,r,x);
    }
    
    int query2(int o,int l,int r,int x)
    {
        if (l == r)
            return sum[o];
        int mid = (l + r) >> 1;
        if (x <= mid)
            return query2(o * 2,l,mid,x);
        else
            return query2(o * 2 + 1,mid + 1,r,x);
    }
    
    int query3(int o,int l,int r,int x)
    {
        if (l == r)
            return maxx2[o];
        int mid = (l + r) >> 1;
        if (x <= mid)
            return query3(o * 2,l,mid,x);
        else
            return query3(o * 2 + 1,mid + 1,r,x);
    }
    
    int main()
    {
        //freopen("data.txt","r",stdin);
        //freopen("ans.txt","w",stdout);
        scanf("%d",&n);
        for (int i = 1; i <= n; i++)
        {
            scanf("%d",&a[i]);
            fa[i] = i;
        }
        build(1,1,n);
        scanf("%d",&q);
        while (q--)
        {
            char ch[5];
            int x,y;
            scanf("%s",ch);
            if (ch[0] == 'U')
            {
                scanf("%d%d",&x,&y);
                int fx = find(x),fy = find(y);
                if (fx != fy)
                {
                       int temp1 = query3(1,1,n,fx),temp2 = query3(1,1,n,fy);
                       int temp = max(temp1,temp2);
                    fa[fx] = fy;
                    update4(1,1,n,find(x),temp);
                }
            }
            else if (ch[0] == 'A' && ch[1] == '1')
            {
                scanf("%d%d",&x,&y);
                update1(1,1,n,x,y); //单点修改最大值
                int temp = query1(1,1,n,x) + query2(1,1,n,find(x));
                if (temp > query3(1,1,n,find(x)))
                    update4(1,1,n,find(x),temp);
            }
            else if (ch[0] == 'A' && ch[1] == '2')
            {
                scanf("%d%d",&x,&y);
                update2(1,1,n,find(x),y);  //连通块修改最大值
            }
            else if (ch[0] == 'A' && ch[1] == '3')
            {
                scanf("%d",&x);
                all += x;
            }
            else if (ch[0] == 'F' && ch[1] == '1')
            {
                scanf("%d",&x);
                int temp = query1(1,1,n,x) + query2(1,1,n,find(x)); //单点查询+区间求和
                //printf("%d %d
    ",query1(1,1,n,x),query2(1,1,n,find(x)));
                printf("%d
    ",temp + all);
            }
            else if (ch[0] == 'F' && ch[1] == '2')
            {
                scanf("%d",&x);
                printf("%d
    ",query3(1,1,n,find(x)) + all); //单点查询连通块
            }
            else if (ch[0] == 'F' && ch[1] == '3')
                printf("%d
    ",maxx2[1] + all);
        }
    
        return 0;
    }

    听说还能用左偏树做?以后再回来填坑.

  • 相关阅读:
    将Color的格式转变成颜色值
    F# 学习笔记 1 基础学习
    GridView 72般绝技
    前台直接读取Web.config中的值的方法
    根据属性名称 获取对象的属性值
    字符集与字符编码简介(转)
    一个WinForm程序配置信息的简单模型和维护工具——设计说明
    扩展DLL调用扩展DLL的LINK2001错误的解决办法之一
    CProfile : 读写私有INI配置文件
    日记:如何在MFC中使用Winsock2
  • 原文地址:https://www.cnblogs.com/zbtrs/p/8419771.html
Copyright © 2011-2022 走看看