模板练习(LUOGU)

1:并查集

P3183食物链
#define man 300050

int fa[man],opt,x,y,fx,fy,n,k,ans=0;

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

int main(){
    n=read();k=read();
    for(rint i=1;i<=3*n;i++) fa[i]=i;
    //[1,n]同类;[n+1,2*n]猎物;[2*n+1,3*n]天敌;
    for(rint i=1;i<=k;i++){
        opt=read();x=read();y=read();
        if(x>n||y>n){    ans++;continue;}
        if(opt==1){
            if(find(x+n)==find(y)||find(x+n+n)==find(y)){    ans++;continue;}
            //y是x的猎物或者天敌,谎言
            fa[find(x)]=find(y);//x的同类是y的同类
            fa[find(x+n)]=find(y+n);//x的猎物是y的猎物
            fa[find(x+n+n)]=find(y+n+n);//x的天敌是y的天敌
        }
        else if(opt==2){
            if(find(x)==find(y)||find(x+n+n)==find(y)){    ans++;continue;}
            //x是y的同类或者y是x的天敌,谎言
            fa[find(x)]=find(y+n+n);//y的天敌是x
            fa[find(x+n)]=find(y);//x的猎物是y
            fa[find(x+n+n)]=find(y+n);//x的天敌是y的猎物(由循环关系可得)
        }
    }
    cout<<ans<<endl;
    return 0;
}

 

2.单调队列

P1638逛画展
int n,m;
int pos[2050];//第i个画师的最后出现的下标
int pic[1000050];//画作
int cnt,l=1;//已经出现的画师的数量及不断更新的左端点
int ml=0,mr=0,ans=1e9+7;//最终答案的左右端点及区间的长度

int main(){
    n=read();m=read();
    memset(pos,0,sizeof(pos));
    for(rint i=1;i<=n;i++){
        pic[i]=read();
        if(!pos[pic[i]]) cnt++;//如果之前的画师没有出现过,那么cnt+1
        pos[pic[i]]=i;//将画师的下标更新到最新的一幅
        while(l!=i && l<pos[pic[l]]) l++;//如果最左边的画师的作品在后面的枚举中出现过,那么就可以向后移动一个
        if(cnt==m && i-l+1<ans)//如果数量足够并且区间的长度更有,那么更新
            ml=l,mr=i,ans=i-l+1;
    }
    cout<<ml<<" "<<mr<<endl;
    return 0;
}

 3.差分约束

求最小值时用最长路,求最大值是用最短路

P3275 [SCOI2011]糖果

#define man 1000050

int n,m;

struct edge{    int next,to,dis;}e[man];
int head[man<<1],num=0;

inline void add(int from,int to,int dis){
    e[++num]=(edge){head[from],to,dis};
    head[from]=num;
}

int dis[man],vis[man],cnt[man];

inline void spfa(int s){
    queue<int>q;
    memset(dis,0,sizeof(dis));
    memset(vis,0,sizeof(vis));
    //memset(cnt,0,sizeof(cnt));
    dis[s]=0;vis[s]=0;q.push(s);
    do{
        int u=q.front();q.pop();vis[u]=0;cnt[u]++;
        if(cnt[u]>n){    printf("-1\n");exit(0);}
        for(rint i=head[u];i;i=e[i].next){
            int to=e[i].to;
            if(dis[to]<dis[u]+e[i].dis){
                dis[to]=dis[u]+e[i].dis;
                if(!vis[to]){
                    vis[to]=1;
                    q.push(to);
                }
            }
        }
    }while(q.size());
}

int main(){
    //printf("%.3lf M\n",(double)sizeof(e)/(1<<20));
    n=read();m=read();
    for(rint i=1,opt,x,y;i<=m;i++){
        opt=read();x=read();y=read();
        if(opt==1) add(x,y,0),add(y,x,0);
        if(opt==2) add(x,y,1);
        if(opt==3) add(y,x,0);
        if(opt==4) add(y,x,1);
        if(opt==5) add(x,y,0);
        if(opt%2==0&&x==y){
            printf("-1\n");
            return 0;
        }
    }
    for(rint i=n;i>=1;i--) add(0,i,1);
    spfa(0);
    long long ans=0;
    for(rint i=1;i<=n;i++){
        ans+=dis[i];
    }
    printf("%lld\n",ans);
    return 0;
}

4.二分图匹配

P2055 假期的宿舍

#define man 55

int T,n;
int a[man],b[man],c[man][man],tot,ans;
int used[man],link[man];

bool find(int s){
    for(rint i=1;i<=n;i++){
        if(a[i]==1)
            if(c[s][i]==1&&used[i]==0){
                used[i]=1;
                if(link[i]==0||find(link[i])){
                    link[i]=s;
                    return 1;
                }
            }
    }
    return 0;
}

int main(){
    T=read();
    while(T--){
        n=read();
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
        memset(c,0,sizeof(c));
        memset(link,0,sizeof(link));
        for(rint i=1;i<=n;i++) a[i]=read();
        for(rint i=1;i<=n;i++) b[i]=read();
        for(rint i=1,x;i<=n;i++)
            for(rint j=1;j<=n;j++){
                x=read();
                if(x==1||i==j)
                    c[i][j]=1;
            }
        ans=0,tot=0;
        for(rint i=1;i<=n;i++){
            memset(used,0,sizeof(used));
            if(a[i]==0||(a[i]==1&&b[i]==0)){
                tot++;
                if(find(i)) ans++;
            }
        }
        if(ans==tot) printf("^_^\n");
        else printf("T_T\n");
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/Slager-Z/p/9906863.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值