hdu6251(基环树)

传送门:http://acm.hdu.edu.cn/showproblem.php?pid=6251

题意:有一个n个点的图,有n条边(基环树),每条边有一种颜色,现在有m次操作(前后有影响),每次操作后求出当前的Region数(同一个Region是连通的且颜色一样)。

思路:采用map记录每一个节点所连边的颜色数,再通过dfs求出环,并记录哪些边在环上,以及用map来统计环上的颜色。通过每个节点所连边的颜色数以及环上颜色数来求出初始Region数cnt(不要用搜索求,tle到死!!)。每次更新的时候判断是否在环上,如果不在直接根据两边节点情况判断来更新cnt,如果在环上还要根据环上的颜色来更新cnt。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5+100;
vector<int>g[maxn];
typedef pair<int,int> P;
map<P,int>mpc,vis,mploop;
map<int,int>mppc[maxn],lpmp;
int cnt = 0;
bool vs[maxn];
int keyp;
int dfs2(int now,int fa)
{
    if(vs[now])
    {
        P pp;
        pp.first = min(now,fa);
        pp.second = max(now,fa);
        mploop[pp] = 1;
        lpmp[mpc[pp]]++;
        keyp = now;
        return 1;
    }
    vs[now] = 1;
    for(int i = 0;i<g[now].size();i++)
    {
        if(g[now][i] == fa)continue;
        int tp = dfs2(g[now][i],now);
        if(tp == 1)
        {
            P pp;
            pp.first = min(now,fa);
            pp.second = max(now,fa);
            mploop[pp] = 1;
            lpmp[mpc[pp]]++;
            if(keyp == fa)
            {
                return -1;
            }
            else
                return 1;
        }
        else if(tp == -1)return -1;
    }
    return 0;
}
int main()
{
    int t;
    scanf("%d",&t);
    int n,m;
    int cas = 0;
    while(t--)
    {
        cnt = 0;
        map<P,int>::iterator it;
        scanf("%d%d",&n,&m);
        for(int i =0;i<=n;i++)
        {
            g[i].clear();
            mppc[i].clear();
        }
        mpc.clear();mploop.clear();vis.clear();lpmp.clear();
        int x,y,c;
        P p;
        for(int i = 0;i<n;i++)
        {
            scanf("%d%d%d",&x,&y,&c);
            g[x].push_back(y);
            g[y].push_back(x);
            p.first = min(x,y);
            p.second = max(x,y);
            mpc[p] = c;  //每条边对应颜色
        }    
        memset(vs,0,sizeof(vs));
        dfs2(1,-1);
        //每个点所连的颜色数
        for(int i = 1;i<=n;i++)
        {
            for(int j = 0;j<g[i].size();j++)
            {
                p.first = min(i,g[i][j]);
                p.second = max(i,g[i][j]);
                mppc[i][mpc[p]]++;
            }
            cnt += mppc[i].size() - 1;
        }
        if(lpmp.size()==1)cnt ++ ;
        printf("Case #%d:\n",++cas);
        while(m--)
        {
            scanf("%d%d%d",&x,&y,&c);
            p.first = min(x,y);
            p.second = max(x,y);
            if(mpc[p] == c)
            {
                printf("%d\n",cnt);
                continue;
            }
            int rigc = mpc[p];
            //not in circle
            if(!mploop[p])
            {
                if(mppc[x][c]==0)
                {
                    if(mppc[x][rigc] > 1)
                        cnt++;
                }
                else
                {
                    if(mppc[x][rigc] == 1)
                        cnt --;
                }
                if(mppc[y][c]==0)
                {
                    if(mppc[y][rigc] > 1)
                        cnt++;
                }
                else
                {
                    if(mppc[y][rigc] == 1)
                        cnt --;
                }
            }
            //in circle
            else
            {
                if(lpmp.size()==1)
                {
                    cnt++;
                }
                else if(lpmp.size()==2 && lpmp[rigc] == 1)
                {
                    if(lpmp[c])
                    {
                        cnt --;
                    }
                }
                else
                {
                    if(mppc[x][c]==0)
                    {
                        if(mppc[x][rigc] > 1)
                            cnt++;
                    }
                    else
                    {
                        if(mppc[x][rigc] == 1)
                            cnt --;
                    }
                    if(mppc[y][c]==0)
                    {
                        if(mppc[y][rigc] > 1)
                            cnt++;
                    }
                    else
                    {
                        if(mppc[y][rigc] == 1)
                            cnt --;
                    }
                }
                lpmp[rigc]--;
                lpmp[c]++;
            }
            printf("%d\n",cnt);
            mppc[x][c]++;
            mppc[x][rigc]--;
            mppc[y][c]++;
            mppc[y][rigc]--;
            mpc[p] = c;
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值