P1197 [JSOI2008]星球大战

不同的结构形成的结果也不同。。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<stack>
#define MAXN 200010
using namespace std;
int n,m,fa[MAXN*2],key[MAXN*2],ans,out[MAXN*2],anss,k,t=1,a,b;
vector<int > G[MAXN*2];//不开大会RE的 
stack<int > s;
inline int read()//读入优化 
{
    int s=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){s=s*10+c-'0';c=getchar();}
    return s*f;
}
int find(int x)//并查集 
{
    if(fa[x]!=x)
    {
        fa[x]=find(fa[x]);       //路径压缩 
    }
    return fa[x];
}
int onion(int x,int y)
{
    int fx=find(x),fy=find(y);
    if(fx!=fy)
    {
        ans++;//当两个元素不在同一个集合中的时候 用ans记录一下减少了几个联通块
                //也就是说每当有两个不同的集合被合并的时候 联通块数量-1 
        fa[fx]=fy;
    }
}
void init()//输入 
{
    memset(key,1,sizeof(key));
    n=read();m=read();
    for(int i=0;i<n;i++)
    {
        fa[i]=i; 
    }
    for(int i=0;i<m;i++)
    {
        a=read();b=read();
        G[a].push_back(b);//双向存边 
        G[b].push_back(a);
    }    
}
void pre()//预处理 
{
    k=read();
    for(int i=0;i<k;i++)
    {
        a=read();
        s.push(a);//因为要倒序加入 所以就写了个栈 STL 大法好啊 
        key[a]=0;//记录一下哪些点要被删除 然后标记一下 
    }
    for(int i=0;i<n;i++)
    {
        if(key[i])
        {
            for(int j=0;j<G[i].size();j++)//将所有剩余的点跑一次并查集 
            {
                int v=G[i][j];
                if(key[v])//如果相连的另一个点不在图中 就不能加入 
                {
                    onion(i,v);
                }
            }
        }
    }
    anss=n-k-ans;ans=0;out[k]=anss;//这时候算的是最后一个数据 也就是所有的边都被删之后剩余联通块数
    //用anss记录剩余联通块 n-k-ans就是n-k个元素减去联通块减少的数量 就是剩余的数量了 
}
void work()
{
        while(!s.empty())//倒序加入 
    {
        int v=s.top();s.pop();
        for(int j=0;j<G[v].size();j++)
        {
            int dd=G[v][j];
            if(key[dd])//还是判断一下是否在图中 
            {
                onion(dd,v);    
            }
        }
        anss=anss-ans+1;//因为一个新的点加入之后 本身联通块就要多一个 所以这里不是anss-ans而是anss-ans+1 
        out[k-t]=anss;//记录 
        ans=0;t++;key[v]=1; //每次记得要把ans清零 还有key【v】为true 也就是这个点已经加入到图中了  
    }
}
void outit()
{
    for(int i=0;i<=k;i++)
    {
        cout<<out[i]<<endl; //我是倒序保存然后正序输出的 正序保存倒序输出也ok 
    }
}
int main()
{
    std::ios::sync_with_stdio(false);//如果不用scanf的话记得开优化 不然有一个点会TLE的 
    std::cin.tie(0);//其实就是因为我不用链表存 而是用vector 所以才慢的 
    init();
    pre();
    work();
    outit();
    return 0;
}

我的代码只通过了50%..


#include <bits/stdc++.h>

using namespace std;

int n,m;
int k;
int const maxn =400010;

int f[maxn],vis[maxn];
int cnn;
struct Edge {
    int from,to;
    Edge(int _from,int _to):from(_from),to(_to){}
};
queue<Edge> all,res;
stack<int> ans;
stack<int> star;
vector<Edge> edges;
vector<int> G[maxn],G2[maxn];
int find_f(int x) {

  return f[x]!=x?f[x]=find_f(f[x]):x;

}

void add_edges(int from,int to)
{
    Edge e1(from,to),e2(to,from);
    edges.push_back(e1);
    G[e1.from].push_back(edges.size()-1);
    edges.push_back(e2);
    G[e2.from].push_back(edges.size()-1);

}

void union_set(int x,int y) {

    int rx = find_f(x);

    int ry = find_f(y);

    if(rx!=ry) {

        f[ry] = rx;
        cnn--;

    }

}



bool query(int x,int y){

    int rx = find_f(x);

    int ry = find_f(y);

    if(rx!=ry) return false;

    return true;

}


void work() {
    int label = star.top();
    star.pop();

    if(label==-1) {
       stack<int> tt=star;
       set<int> s;
       while(!tt.empty())
       {
           int temp = tt.top();tt.pop();
           for(int i=0;i<G[temp].size();i++) {
             s.insert(G[temp][i]);
             s.insert(G[temp][i]^1);
           }

       }
       for (int i=0;i<edges.size();i+=2)
       {
           if(s.count(i)==0) union_set(edges[i].from,edges[i].to);
       }
        return;
    }
     vis[label] = 1;
    for(int i=0;i<G[label].size();i++)
    {
        Edge e1 = edges[G[label][i]];
        Edge e2 = edges[G[label][i]^1];
        if(vis[e1.to]) {
            union_set(e1.from,e1.to);
        }
        if(vis[e2.from]) {
            union_set(e2.from,e2.to);
        }

    }
}

int main() {

   // freopen("in.txt","r",stdin);
    std::ios::sync_with_stdio(false);//如果不用scanf的话记得开优化 不然有一个点会TLE的
    std::cin.tie(0);//其实就是因为我不用链表存 而是用vector 所以才慢的
    cin>>n>>m;
    int fo,t;
    for (int i=0;i<m;i++)
    {
        cin>>fo>>t;
       add_edges(fo,t);
    }

    cin>>k;
    cnn=n;
    for (int i=0;i<n;i++) {
            vis[i] = 1;
            f[i] = i;
    }
    for (int i=0;i<k;i++)
    {
        cin>>fo;
        vis[fo] = 0;
        star.push(fo);
    }
    star.push(-1);

    while(!star.empty())
    {
        work();
        ans.push(cnn-star.size());

    }
    while(!ans.empty())
    {
        cout<<ans.top()<<endl;
        ans.pop();
    }


}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值