zoukankan      html  css  js  c++  java
  • ZOJ3261并查集逆向处理

    题意:
          给你一些点,还有一些边,每个点上都有一个权值,然后有一些询问,分为两种,
    query a 询问与a直接或者间接想连的点中最大权值的是那个点,输出那个点,如果那个点的权值小于等于a的权值,那么就输出-1,还有另一种操作就是destroy a b意思是删除a b的关系。


    思路:

          比较基础的并查集题目,看到删边,很容易想到逆向离线处理,先把最终的状态建立出来,然后对于询问逆向处理,正向是删边,那么逆向肯定是加边了,更新最优的话也是比较简单的并查集小变种(也就是平时说的带权并查集),一开始wa了好几次,原因是没有注意一点,就是最大值相等的要编号小的点,这个注意下,别的没啥,具体细节看代码。


    #include<map>
    #include<stdio.h>
    #include<string.h>
    
    #define N_node 10000 + 50
    #define N_edge 20000 + 50
    #define N_q 50000 + 50
    
    using namespace std;
    
    typedef struct
    {
       int a ,b;
    }EDGE;
    
    typedef struct
    {
       int key ,a ,b ,ans;
    }QQ;
    
    int mer[N_node] ,num[N_node];
    int _max[N_node] ,maxid[N_node];
    map<int ,map<int ,int> >mark;
    EDGE E[N_edge];
    QQ Q[N_q];
    
    int finds(int x)
    {
        x == mer[x] ? x : mer[x] = finds(mer[x]);
    }
    
    int main ()
    {
        int n ,m ,q ,i;
        char str[10];
        int mk = 0;
        while(~scanf("%d" ,&n))
        {
            if(mk) printf("
    ");
            mk = 1;
            for(i = 1 ;i <= n ;i ++)
            scanf("%d" ,&num[i]);
            scanf("%d" ,&m);
            for(i = 1 ;i <= m ;i ++)
            {
                scanf("%d %d" ,&E[i].a ,&E[i].b);
                E[i].a ++ ,E[i].b ++;
            }
            scanf("%d" ,&q);
            mark.clear();
            for(i = 1 ;i <= q ;i ++)
            {
                scanf("%s" ,str);
                if(str[0] == 'q')
                {
                    scanf("%d" ,&Q[i].a);
                    Q[i].key = 1;
                    Q[i].a ++;
                }
                else
                {
                    scanf("%d %d" ,&Q[i].a ,&Q[i].b) ,Q[i].key = 2;
                    Q[i].a ++ ,Q[i].b ++;
                    mark[Q[i].a][Q[i].b] = mark[Q[i].b][Q[i].a] = 1;
                }
    
            }
            for(i = 1 ;i <= n ;i ++)
            maxid[i] = mer[i] = i ,_max[i] = num[i];
            for(i = 1 ;i <= m ;i ++)
            {
                if(mark[E[i].a][E[i].b]) continue;
                int x = finds(E[i].a);
                int y = finds(E[i].b);
                if(x != y)
                {
                    mer[x] = y;
                    if(_max[y] < _max[x] || _max[y] == _max[x] && maxid[y] > maxid[x])
                    {
                        _max[y] = _max[x];
                        maxid[y] = maxid[x];
                    }
                }
            }
            for(i = q ;i >= 1 ;i --)
            {
                if(Q[i].key == 1)
                {
                    int x = finds(Q[i].a);
                    if(_max[x] > num[Q[i].a]) Q[i].ans = maxid[x] - 1;
                    else Q[i].ans = -1;
                }
                else
                {
                    int x = finds(Q[i].a);
                    int y = finds(Q[i].b);
                    if(x != y)
                    {
                        mer[x] = y;
                        if(_max[y] < _max[x] || _max[y] == _max[x] && maxid[y] > maxid[x])
                        {
                            _max[y] = _max[x];
                            maxid[y] = maxid[x];
                        }
                    }
                }
            }
            for(i = 1 ;i <= q ;i ++)
            if(Q[i].key == 1) printf("%d
    " ,Q[i].ans);
    
        }
        return 0;
    }
    


  • 相关阅读:
    MySQL连接数过多登录不上
    Linux中盘符的两种挂载方法
    Linux杀毒软件ClamAV初次体验
    VS2013开发asmx接口根据ID查询对象
    VS2013开发asmx接口返回一个自定义XML
    VS2013开发一个简单的asmx接口程序
    Java编译过程(传送门)
    凡人和神学习和使用软件的七个层次
    CentOS7 限制SSH密码尝试次数
    马云是如何招聘到多隆这样的牛人的?(转)
  • 原文地址:https://www.cnblogs.com/csnd/p/12062432.html
Copyright © 2011-2022 走看看