[NOI2001]食物链

https://www.luogu.org/problemnew/show/P2024

我写了三四天,写了个巨笨的方法
其实2关系能弄出环来,1关系就是合并集合
注意各种情况下的合并,环和环怎么合并,单独集合和环怎么合并,单独集合和单独集合怎么合并

#include<bits/stdc++.h>
using namespace std;
int n,k;
vector <int> S[50000*3+100];  //前50000*2堆用来存环(保证够用),后5000堆存未成环的堆
int rear=100000;   //指向最后5000堆
int cnt;   //已成多少个环
int M[50000+100];   //Mi表示动物i在哪一堆里
void merge(int x,int y){    //把两个堆合并
    int temp=min(x,y);
    int temp1=max(x,y);//这里直接把下标大的堆的东西整到下标小的堆里去,这种合并任何情况都不会出问题
    for(vector<int>::iterator it=S[temp1].begin();it!=S[temp1].end();it++){
        S[temp].push_back(*it);            
    }
    
    for(vector<int>::iterator it=S[temp1].begin();it!=S[temp1].end();it=S[temp1].begin()){
        M[(*it)]=temp;     //改一下*it的堆指向
        S[temp1].erase(it);     //删了大堆
    }
}
int main(){
    for(int i=0;i<50000+100;i++)
        M[i]=-1;
    cin>>n>>k;
    int f,x,y,ans=0;
    for(int i=1;i<=k;i++){
        scanf("%d%d%d",&f,&x,&y);
        if(x>n||y>n){
            ans++;
            continue;
        }
        if(f==2&&x==y)   //自己不能吃自己
        {
            ans++;continue;    
        } 
        if(f==2 && M[x]!=-1 && M[x]==M[y] ){      //同族不能互吃
            ans++;continue;
        }
        if(f==2 && M[x]!=-1 && M[y]!=-1 && M[x]<100000 && M[y]<100000 && (M[x]/3==M[y]/3) && ( (M[y]%3==0&&M[x]%3==1) || (M[y]%3==1&&M[x]%3==2) || (M[y]%3==2&&M[x]%3==0)))           //不能互吃
        {
            ans++;continue;
        }
        if(f==1 && M[x]!=-1 && M[y]!=-1 && M[x]<100000 && M[y]<100000 && ((M[x]/3)==(M[y]/3)) && M[x]!=M[y]){                      //异族不能1操作
            ans++;continue;       
        }
        if(f==1){   //合并 
            if(M[x]==-1&&M[y]==-1){    //都是新来的 
                S[++rear].push_back(x);  //5001后新建堆   插入 更新M 
                M[x]=rear;  
                if(y!=x)      //x和y要是一样数组里放个x就完事了不放y了   
                    S[rear].push_back(y);
                    M[y]=rear;
                continue;
            }
            if(M[x]!=-1&&M[y]==-1){    //y是新来的 
                S[M[x]].push_back(y);     //插入 
                M[y]=M[x];              //更新M 
                continue;
            }
            if(M[x]==-1&&M[y]!=-1){     //x是新来的 
                S[M[y]].push_back(x);      //
                M[x]=M[y];
                continue;
            }
            if(M[x]!=-1&&M[y]!=-1&&M[x]!=M[y]){         //由于之前已经判过不可合并了,他俩现在必可合并   都有堆 
                if((M[x]>=100001&&M[y]>=100001)||(M[x]<100001&&M[y]>=100001)||(M[y]<100001&&M[x]>=100001)){ // 直接合并 
                    merge(M[x],M[y]);
                    continue;
                }
                if(M[x]<100001&&M[y]<100001&&(M[x]/3)!=(M[y]/3)){  //“环”合并
                
                    int a1=(M[x]-1);    //合并上家 
                    if(M[x]%3==0)
                        a1=M[x]+2;  
                    int b1=(M[y]-1);
                    if(M[y]%3==0)
                        b1=M[y]+2;
                    int a2=(M[x]+1);    //合并下家 
                    if(M[x]%3==2)
                        a2=M[x]-2;
                    int b2=(M[y]+1);
                    if(M[y]%3==2)
                        b2=M[y]-2;
                    merge(M[x],M[y]);        //合并 
                    merge(a1,b1);
                    merge(a2,b2); 
                    continue;
                }
            }
        }
        else{
            //k==2
            if((M[x]/3==M[y]/3) && ((M[x]%3==0&&M[y]%3==1) || (M[x]%3==1&&M[y]%3==2)||(M[x]%3==2&&M[y]%3==0 )  ))
            {    
                //已经知道x吃y了,跳过此条信息
                continue;
            }    
            if(M[x]==-1&&M[y]==-1){          //都是新来的    新建环
                S[cnt*3+0].push_back(x);         //默认放01  0吃1 1吃2 2吃0 
                M[x]=cnt*3+0;        
                S[cnt*3+1].push_back(y);
                M[y]=cnt*3+1;      
                cnt++;
                continue;
            }
            if(M[x]!=-1&&M[y]==-1){    //y新来的 
                if(M[x]<100001){         //x在某个圈里 
                    if(M[x]%3!=2){     //把y放x下家 
                        S[M[x]+1].push_back(y);
                        M[y]=M[x]+1;
                        continue;
                    }
                    else{
                        S[M[x]-2].push_back(y);
                        M[y]=M[x]-2;
                        continue;
                    }
                }
                else{   //x不在圈里 
                    merge(cnt*3+0,M[x]);   //新建圈  x堆放圈0位置 
                    S[cnt*3+1].push_back(y);    //y放圈1位置 
                    M[y]=cnt*3+1;  
                    cnt++;
                    continue;
                }
            }
            if(M[y]!=-1&&M[x]==-1){    //x是新来的 
                if(M[y]<100001){     //y在圈里 
                    if(M[y]%3!=0){   //把x放y上家 
                        S[M[y]-1].push_back(x);
                        M[x]=M[y]-1;
                        continue;
                    }
                    else{
                        S[M[y]+2].push_back(x);
                        M[x]=M[y]+2;
                        continue;
                    }
                }
                else{   //y不在 
                    S[cnt*3+0].push_back(x);            //新建圈 
                    M[x]=cnt*3+0;
                    merge(cnt*3+1,M[y]); 
                    cnt++;
                    continue;
                }
            }
            if(M[x]!=-1&&M[y]!=-1){    //xy都是堆 
                if(M[x]>=100001&&M[y]>=100001){  //都不在圈里 
                    merge(cnt*3+0,M[x]);   //新建圈 
                    merge(cnt*3+1,M[y]);
                    cnt++;
                    continue;
                }
                if(M[x]<100001&&M[y]>=100001){    //x在圈,y不在 
                    if(M[x]%3==2){      //把y放x下家 
                        merge(M[x]-2,M[y]);
                        continue;
                    }
                    else{
                        merge(M[x]+1,M[y]);
                        continue;
                    }
                }   
                if(M[y]<100001&&M[x]>=100001){      //y在圈,x不在 
                    if(M[y]%3==0){     //把x放y上家 
                        merge(M[y]+2,M[x]);
                        continue;
                    }
                    else{
                        merge(M[y]-1,M[x]);
                        continue;
                    }
                }
                if(M[x]<100001&&M[y]<100001&&M[x]/3!=M[y]/3){     //都在圈 
                    //环合并
                    int a1=(M[x]-1);
                    if(M[x]%3==0)
                        a1=M[x]+2;
                    int b1=(M[y]-1);
                    if(M[y]%3==0)
                        b1=M[y]+2;
                    int a2=(M[x]+1);
                    if(M[x]%3==2)
                        a2=M[x]-2;
                    int b2=(M[y]+1);
                    if(M[y]%3==2)
                        b2=M[y]-2;
                    merge(M[x],b1);
                    merge(M[y],a2);
                    merge(a1,b2);
                    continue;
                }
            }
        }
    }
    cout<<ans<<endl;
    return 0;
}
原文地址:https://www.cnblogs.com/spzeno/p/11188029.html