• [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;
    }
  • 相关阅读:
    给Linux添加google搜索命令
    安卓设置脚本开机自启动
    重读The C programming Lanuage 笔记四:c预处理
    重读The C programming Lanuage 笔记三:简单计算器程序
    重读The C programming Lanuage 笔记二:运算符优先级
    重读The C programming Lanuage 笔记一:类型转换
    【 转】 C/C++结构体和联合体的区别
    python 柯里化 和装饰器
    qq bug 一个
    网站收集
  • 原文地址:https://www.cnblogs.com/spzeno/p/11188029.html
Copyright © 2020-2023  润新知