首页 > 其他分享 >[lnsyoj1015/luoguP1197/JSOI2008]星球大战starwar

[lnsyoj1015/luoguP1197/JSOI2008]星球大战starwar

时间:2024-09-28 17:00:50浏览次数:6  
标签:lnsyoj1015 return int JSOI2008 连通 fa 操作 starwar include

题意

给出一个 \(n\) 个点,\(m\) 条边的无向图,对其进行 \(k\) 次操作,每次操作会删除一个当前无向图中存在的点及其相邻的边,求原图 和每次操作之后的图的连通块个数

sol

由于需要计算连通块个数,可以自然的想到使用并查集解决。然而,删除某个点后,我们无法通过并查集快速地得知其与其他点是否直接联通,也就无法快速地计算。
考虑按照操作的逆序来计算,那么就相当于在一个 \(n-k\) 个点的无向图中,每次操作添加一个点,并添加一些与其相邻的边,求原图和每次操作之后的图的连通块个数。这样,就可以通过并查集来解决这个问题了。

代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <unordered_map>
#include <vector>

#define x first 
#define y second 

using namespace std;
typedef pair<int, int> PII;

const int N = 400005;

int n, m, k;
int g[N];
PII edges[N];
unordered_map<int, int> depth;
vector<PII> edge[N];
int fa[N];
int ans[N];

int find(int x){
    if (fa[x] == x) return x;
    return fa[x] = find(fa[x]);
}

int main(){
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= m; i ++ ) {
        int x, y;
        scanf("%d%d", &x, &y);
        edges[i] = {x, y};
    }

    scanf("%d", &k);
    for (int i = 1; i <= k; i ++ ) {
        scanf("%d", &g[i]);
        depth[g[i]] = k - i + 1;
    }
    
    for (int i = 1; i <= m; i ++ ) {
        int dx = depth[edges[i].x], dy = depth[edges[i].y];
        edge[max(dx, dy)].push_back(edges[i]);
    }

    for (int i = 1; i <= n; i ++ ) fa[i] = i;
    int cnt = n - k;

    for (int d = 0; d <= k; d ++ , cnt ++ ){
        // printf("#depth: %d\n", d);
        for (auto e : edge[d]){
            // printf("%d %d\n", e.x, e.y);
            int fx = find(e.x), fy = find(e.y);
            if (fx == fy) continue;
            cnt -- ;
            fa[fx] = fy;
        }

        ans[d] = cnt;
    }

    for (int i = k; i >= 0; i -- ) printf("%d\n", ans[i]);

    return 0;
}

标签:lnsyoj1015,return,int,JSOI2008,连通,fa,操作,starwar,include
From: https://www.cnblogs.com/XiaoJuRuoUP/p/-/lnsyoj1015_luoguP1197

相关文章

  • P4036 [JSOI2008] 火星人
    #include<bits/stdc++.h>#defineintlonglongusingnamespacestd;intlen;intm;intrt=0;inthas[1000010];voidinit(){ srand(1);has[0]=1;for(inti=1;i<=1000000;i++)has[i]=has[i-1]*101;//cout<<......
  • C130 并查集 P1197 [JSOI2008] 星球大战
    视频链接:  P1197[JSOI2008]星球大战-洛谷|计算机科学教育新生态(luogu.com.cn)//并查集#include<iostream>#include<cstdio>#include<cstring>usingnamespacestd;constintN=400005;inth[N],from[N],to[N],ne[N],idx;voidadd(intu,intv){from[......
  • P1197 [JSOI2008] 星球大战
    原题链接题解,请看题解区第一篇,看一遍就会了code#include<bits/stdc++.h>usingnamespacestd;intfa[400005]={0};intfinds(intnow){returnfa[now]=(fa[now]==now?now:finds(fa[now]));}vector<int>G[400005];intbroke[400005];intBroke[400005]={0};intm......
  • P1198 [JSOI2008] 最大数
    原题链接题解1:单调栈+并查集?单调栈特性:栈内元素大小和序号由栈底到栈顶具有单调性,本题大小单调减,序号单调增维护:新元素入栈时,栈内剩余的所有小于该元素的元素出栈,并视新元素为集合首领,然后新元素入栈查询:查询集合首领即可code1#definelllonglong#include<bits/stdc++.h>......
  • P1197 [JSOI2008] 星球大战 题解
    P1197[JSOI2008]星球大战题解题目链接P1197[JSOI2008]星球大战简要思路看完题目的第一印象是——连通性。图论中判断连通性很容易想到并查集,但是并查集只支持合并和查询,并不支持删除,怎么办呢?考虑逆向思维,把删点的过程倒过来,看成加点和连边,那么此题就可以非常方便的用并......
  • 「JSOI2008」最小生成树计数 题解报告
    简要题意现在给出了一个简单无向加权图。你希望知道这个图中有多少个不同的最小生成树。(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的)。输出方案数对\(31011\)取模。SOLUTION这个题求最小生成树的方案所以我们从最小生成树入手(根据kruskal的思路)我们......
  • P4036 [JSOI2008] 火星人
    暴力水过了wwwwwwwwwwwwwww#include<bits/stdc++.h>//================================================//#defineLOCALFLANDREKAWAII#ifndefLOCALconstexprintSIZE(1<<20);charin[SIZE],out[SIZE],*p1=in,*p2=in,*p3=out;#definegetchar(......
  • P4035 [JSOI2008]球形空间产生器
    A,B,球心坐标分别为\((a_1,a_2,a_3....),(b_1,b_2,b_3....),(c_1,c_2,c_3....)\)则\(dist^2=(a_1-c_1)^2+(a_2-c_2)^2+(a_3-c_3)^2\)......\(=(b_1-c_1)^2+(b_2-c_2)^2......
  • P1198 JSOI2008 最大数
    P1198JSOI2008最大数-洛谷|计算机科学教育新生态(luogu.com.cn)采用ST表维护RMQ。对于插入操作,设插入后数列长度变为\(n\),我们只需重新修改满足\(i+2^j-......
  • BZOJ 1012: [JSOI2008]最大数maxnumber
    题目链接:​​传送门​​时隔一年再写一遍#include<iostream>#include<cstdio>#include<cstring>#include<cstdlib>#include<complex>#include<algorithm>#include<cl......