码迷,mamicode.com
首页 > Web开发 > 详细

LGOJ P1197 【[JSOI2008]星球大战】

时间:2019-11-07 23:23:53      阅读:140      评论:0      收藏:0      [点我收藏+]

标签:tac   情况   dig   代码   else   bool   cin   att   amp   

我十分喜欢自带大常数的STL

思路都是反着来,先把该删的节点都删除,再一个一个往图里面加。
加节点的时候分类讨论:

假设当前要加的节点是 u ,用

set<int> S;

来存储 u 节点直接连接的点 v 的所属集合的值 find(v) ,这样 S.size() 的值就表示 u 节点究竟链接了几种不同的联通块。再分类讨论:

if (S.size() == 0)tpc++;//若这是一个单独的点
                        //添加之后tpc++
else if (S.size() == 1);//若这个点只连接了一个联通块
                        //那么她的存在就没有什么所谓
else
{
    tpc -= S.size();    //如果这个点连接了两个以上的块
                        //那么显然tpc要减去(S.size()-1)
    tpc++;
}

注:tpc == type_count.

剩下的事情就简单了,先dfs一次求末状态的块数量,链表存贮 k 次操作,倒着加点,再倒着输出即可。


// P1197.cpp: 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include<bits/stdc++.h>
using namespace std;
inline int read()
{
    char c = getchar();
    int x = 0;
    bool minus = 0;
    for (; !isdigit(c); c = getchar())
        if (c == '-')minus = 1;
    for (; isdigit(c); c = getchar())
        x = x * 10 + c - '0';
    if (minus)return -x;
    return x;
}
const int M = 200005, N = 400005;
int n, m, k, f[N], tpc;
vector<int> G[N];//Graph
list<int> atk;//attack_list
bool ban[N];//值为1表示当前节点不可用
bool vis[N];//dfs用的数组
list<int>asl;//answer_list
set<int>S;

//普通的并查集
inline int find(int x)
{
    if (f[x] == x)return x;
    return f[x] = find(f[x]);
}

inline void unity(int x, int y)
{
    int u = find(x);
    int v = find(y);
    f[f[u]] = v;
}
//普通的dfs
void dfs(int u)
{
    int v = 9999;
    vis[u] = 1;
    for (int i = 0; i < G[u].size(); i++)
    {
        v = G[u][i];
        if (!ban[v] && !vis[v])
        {
            unity(u, v);
            dfs(v);
        }
    }
}
//核心代码↓
inline void work()
{
    asl.push_front(tpc);//最后的情况放链表首
    for (list<int>::iterator it = atk.begin(); it != atk.end(); it++)
    {
        //欲添加的节点为u,u直接连接的节点为v
        int u = *it;
        S.clear();
        ban[u] = 0;
        for (int j = 0; j < G[u].size(); j++)
        {
            int v = G[u][j];
            if (ban[v])continue;
            //      ↑ v在之前被删除,不能选
            S.insert(find(v));
            unity(u, v);
        }
        
        if (S.size() == 0)tpc++;
        else if (S.size() == 1);
        else
        {
            tpc -= S.size();
            tpc++;
        }
        //tpc放asl首
        asl.push_front(tpc);
    }

}


int main()
{
    cin >> n >> m;
    int u = 0, v = 0;
    for (int i = 1; i <= m; i++)
    {
        u = read();
        v = read();
        G[u].push_back(v);
        G[v].push_back(u);
    }
    k = read();
    int t = 0;
    for (int i = 1; i <= k; i++)
    {
        t = read();
        ban[t] = 1;
        atk.push_front(t);
    }
    for (int i = 0; i < n; i++)f[i] = i;

    for (int i = 0; i < n; i++)
    {
        if (!vis[i] && !ban[i])
        {
            tpc++;
            dfs(i); 
        }
    }
    work();
    for (list<int>::iterator it = asl.begin(); it != asl.end(); it++)
        printf("%d\n", *it);

    return 0;
}

LGOJ P1197 【[JSOI2008]星球大战】

标签:tac   情况   dig   代码   else   bool   cin   att   amp   

原文地址:https://www.cnblogs.com/kion/p/11816190.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!