HDU - 6251 Inkopolis (2017 CCPC FInal I)(带环树上维护颜色块数量)

本博客介绍了一个算法问题,目标是在一个特定的图结构中,即Inkopolis城市模型,计算修改道路颜色后形成的彩色区域数量。通过深度优先搜索找到环,并使用map数据结构来维护节点周围的颜色种类,从而高效地更新和查询颜色区域。

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

Inkopolis

Time Limit: 24000/12000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 322    Accepted Submission(s): 80


 

Problem Description


Inkopolis is the city in which Inklings live in, it can be regarded as an undirected connected graph with exactly N vertices and N edges between vertices. It is guaranteed that the graph doesn’t contain duplicated edges or self loops. Inklings can splatter a special type of colored ink to decorate the roads they live in. Inklings are capricious so they often change the color of the roads to celebrate the upcoming Splatfest.
The Splatfest lasts for exactly M days, on each day Inklings will splatter ink on exactly one road, the color on this road will be coverd by the new color of the ink. At the end of each day, they wonder how many different colored regions are there in the Inkopolis. A colored region is a set of connected roads with same color, to be clear, two roads are in the same colored region if they have the same color and share a common vertex.

 

 

Input

The first line of the input gives the number of test cases, T. T test cases follow.
For each test case, the first line contains two integers N and M, where N is the number of vertexes and roads in Inkopolis, and M is the number of days that Splatfest lasts.
Following N lines describe the roads between the vertexes. Each line contains 3 integers x, y, c, representing there is a road with color c between the xth and the ythvertex.
Next following M lines describe the operations on each day. Each line contains 3 integers x, y, c, representing an operation that Inklings splatter the ink with color c to the road between the xth and the yth vertex, it is guaranteed that there is such a road.
1≤T≤100
3≤N≤2×105
1≤M≤2×105
1≤x,y,c≤n
∑N,∑M≤106

 

 

Output

For each test case, output one line containing “Case #x:” first, where x is the test case number (starting from 1).
The following M lines each consists of an integer which is the number of colored regional in Inkopolis after each day.

 

 

Sample Input

 

2 4 3 4 2 4 2 3 3 3 4 2 1 4 1 3 4 2 2 3 4 3 4 3 4 4 1 2 1 2 3 1 3 4 1 4 1 1 1 2 2 3 4 2 2 3 2 4 1 4

 

 

Sample Output

 

Case #1: 4 3 3 Case #2: 2 4 2 2

 

 

Source

2017中国大学生程序设计竞赛-总决赛-重现赛(感谢哈工大)

 

 

Recommend

liuyiding

 

 

题意:给你只有一个环的树,树上的边有颜色,每次修改一个边的颜色,每次修改后问树上有多少个颜色块。

解题思路:

题目答案就是:

 

f[i]表示节点i周围不同颜色数

对于树:  ans=(\sum f[i]) - (n -1)

对于环:ans=(\sum f[i]) - n

如果环上只有一种颜色: ans=(\sum f[i])-(n-1)

 

那么就是怎么维护这个f[i],和环上的颜色数了。直接上map暴力维护就好了。详见代码

 

#include<bits/stdc++.h>
using namespace std;
const int MAXN=200005;
typedef long long ll;

inline void scan_d(int &ret)
{
    char c;
    ret = 0;
    while ((c = getchar()) < '0' || c > '9');
    while (c >= '0' && c <= '9')
    {
        ret = ret * 10 + (c - '0'), c = getchar();
    }
}

struct edge{
    int u;
    int v;
    int w;
    int next;
}e[MAXN*2];
int edge_num,head[MAXN];
void insert_edge(int u,int v,int w){
    e[edge_num].u=u;
    e[edge_num].v=v;
    e[edge_num].w=w;
    e[edge_num].next=head[u];
    head[u]=edge_num++;
}
int N,M;
map<pair<int,int>,int> G;//保存每条边的颜色
map<int,int> Col[MAXN];//保存每个点周围的颜色的数量
map<int,int> Cir;//保存环上的颜色的数量
int pre[MAXN];//用于深搜回溯
int prew[MAXN];
bool flag=0;
bool vis[MAXN];
bool tag[MAXN];//当前点是否在环上
void dfs(int u,int fa){
    if(flag)
        return;
    vis[u]=1;
    for(int i=head[u];~i;i=e[i].next){
        int v=e[i].v;
        if(v==fa)
            continue;
        if(vis[v]==0){
            pre[v]=u;
            prew[v]=e[i].w;
            dfs(v,u);
        }
        else{
            int ok=u;
            tag[v]=1;
            Cir[e[i].w]++;
            while(ok!=v){
                tag[ok]=1;
                Cir[prew[ok]]++;
                ok=pre[ok];
            }
            flag=1;
        }
        if(flag)
            return;
    }
}

int main(){

    int T;
    scan_d(T);
    for(int ttt=1;ttt<=T;ttt++){
        printf("Case #%d:\n",ttt);
        scan_d(N);
        scan_d(M);

        flag=0;
        edge_num=0;
        Cir.clear();
        G.clear();
        for(int i=1;i<=N;i++){
            Col[i].clear();
            tag[i]=0;
            vis[i]=0;
            head[i]=-1;
        }

        int u,v,w;
        for(int i=1;i<=N;i++){
            scan_d(u);
            scan_d(v);
            scan_d(w);
            G[make_pair(u,v)]=w;
            G[make_pair(v,u)]=w;
            Col[u][w]++;
            Col[v][w]++;
            insert_edge(u,v,w);
            insert_edge(v,u,w);
        }

        dfs(1,1);//深搜找环
        int tot=0;
        int hsize=Cir.size();
        for(int i=1;i<=N;i++)
            tot+=Col[i].size();
        tot-=N;

        while(M--){
            scan_d(u);
            scan_d(v);
            scan_d(w);
            int lw=G[make_pair(u,v)];
            G[make_pair(u,v)]=w;
            G[make_pair(v,u)]=w;

            //把之前的颜色删掉
            if(--Col[u][lw]==0)
                tot--;
            if(--Col[v][lw]==0)
                tot--;

            //把新的颜色加进去
            if(++Col[u][w]==1)
                tot++;
            if(++Col[v][w]==1)
                tot++;

            //环上特殊处理
            if(tag[u]&&tag[v]){
                if(--Cir[lw]==0)
                    hsize--;
                if(++Cir[w]==1)
                    hsize++;
            }

            if(hsize==1)//如果环只有一种颜色
                printf("%d\n",tot+1);
            else
                printf("%d\n",tot);
        }
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值