葡萄庄园 [图论]

葡萄庄园



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;
}
原文地址:https://www.cnblogs.com/zbr162/p/11822441.html