zoukankan      html  css  js  c++  java
  • 葡萄庄园 [图论]

    葡萄庄园



    color{red}{正解部分}

    答案肯定为 一种颜色联通块 和 另一种颜色联通块 的 的大小,
    中存在 “一座桥”, 可以让其中一个颜色通过, 联通两个联通块 .

    于是考虑先预处理出每个颜色的所有联通块的大小, 给每个不同的联通块分配一个编号, 大小记为 size[id]size[id],

    对一个询问 xx, 考虑求出 xx 所处的 33 种颜色联通块与其他颜色 最大, 设为 max_v[x]max\_v[x],

    则对一个点, 它 属于 它所在的 其中一个颜色联通块 和 另一个颜色联通块 的 ,
    所以枚举每个点, 使用这个点的权值去计算出每个联通块之间的 , 记为 intv[a,b]intv[a, b], 可以使用 std::map<int, ll> intv[] 存储 .

    接下来枚举开头提到的那座 “桥” u,vu, v, 再枚举两边联通块的颜色, 分别记为 a=id[u,1/2/3],b=id[v,1/2/3]a = id[u, 1/2/3], b = id[v, 1/2/3]
    在满足 这座 “桥” 允许其中一种颜色通过 的前提下, 使用 size[a]+size[b]intv[a,b]size[a] + size[b] - intv[a, b] 更新 u,vu,v 所在的对应联通块的答案 max_v[]max\_v[] .

    最后询问时, 枚举当前点的 33 种颜色的联通块, 取其中最大的 max_v[]max\_v[] 作为答案即可 .


    color{red}{实现部分}

    #include<bits/stdc++.h>
    #define reg register
    typedef long long ll;
    
    int read(){
            char c;
            int s = 0, flag = 1;
            while((c=getchar()) && !isdigit(c))
                    if(c == '-'){ flag = -1, c = getchar(); break ; }
            while(isdigit(c)) s = s*10 + c-'0', c = getchar();
            return s * flag;
    }
    
    const int maxn = 100005;
    
    int N;
    int M;
    int num0;
    int Id_cnt;
    int A[maxn];
    int head[maxn];
    int vis[maxn][4];
    
    ll size[maxn];
    ll max_v[maxn];
    
    std::map <int, ll> intv[maxn];
    
    struct EDGE{ int u, v, w; } E[maxn];
    
    struct Edge{ int nxt, to, w; } edge[maxn << 1];
    
    void Add(int from, int to, int w){ edge[++ num0] = (Edge){ head[from], to, w }; head[from] = num0; }
    
    void DFS(int k, const int &col, const int &id){
            vis[k][col] = id, size[id] += A[k];
            for(reg int i = head[k]; i; i = edge[i].nxt){
                    int to = edge[i].to;
                    if(col == edge[i].w || vis[to][col]) continue ;
                    DFS(to, col, id);
            }
    }
    
    void Work(){
            ll Ans = 0; int x = read();
            for(reg int col = 1; col <= 3; col ++) Ans = std::max(Ans, max_v[vis[x][col]]);
            printf("%lld
    ", Ans);
    }
    
    int main(){
            N = read(), M = read();
            for(reg int i = 1; i <= N; i ++) A[i] = read();
            for(reg int i = 1; i <= M; i ++){
                    E[i].u = read(), E[i].v = read(), E[i].w = read();
                    Add(E[i].u, E[i].v, E[i].w), Add(E[i].v, E[i].u, E[i].w);
            }
            for(reg int col = 1; col <= 3; col ++)
                    for(reg int j = 1; j <= N; j ++)
                            if(!vis[j][col]) DFS(j, col, ++Id_cnt);
            for(reg int i = 1; i <= N; i ++)
                    for(reg int j = 3; j >= 1; j --)
                            for(reg int k = j-1; k >= 1; k --) 
                                    intv[vis[i][j]][vis[i][k]] += A[i], intv[vis[i][k]][vis[i][j]] += A[i];
            for(reg int i = 1; i <= M; i ++){
                    if(vis[E[i].u][E[i].w] == vis[E[i].v][E[i].w]) continue ;
                    for(reg int col = 1; col <= 3; col ++){
                            if(E[i].w == col) continue ;
                            int x = vis[E[i].u][E[i].w], y = vis[E[i].v][col]; 
                            max_v[x] = std::max(max_v[x], size[x] + size[y] - intv[x][y]); 
                            max_v[y] = std::max(max_v[y], size[x] + size[y] - intv[x][y]);
                            x = vis[E[i].v][E[i].w], y = vis[E[i].u][col];
                            max_v[x] = std::max(max_v[x], size[x] + size[y] - intv[x][y]); 
                            max_v[y] = std::max(max_v[y], size[x] + size[y] - intv[x][y]);
                    }
            }
            int Q_ = read(); 
            while(Q_ --) Work();
            return 0;
    }
    
  • 相关阅读:
    PKU 3984 迷宫问题
    九度 1341 艾薇儿的演唱会
    九度 1335
    SDUT 1198 鞍点计算
    POJ 1363 Rails
    SDUT 1570 C旅行
    HDU 1042 N!
    SDUT 1568 俄罗斯方块
    HDU 1257 最少拦截系统
    POJ 3750 小孩报数问题
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822441.html
Copyright © 2011-2022 走看看