• 小w的魔术扑克(树状数组+并查集)


    题目链接

    满分做法:

    将正反两面连边,发现如果一个连通块的变数>=n条时,那么这个连通块一定能满足保证每个面值都能够被提供至少一次。如果它是一棵树,无论怎么调整,都会漏掉一个面值无法打出。

    于是最后询问的就是一个线段中是否包含一个完整的限制线段(他的起点为一棵树中编号最小的,终点为最大的),这个可以用离线树状数组解决,把询问线段和限制线段按照右端点从小到大排序。

    一次处理询问,把右端点小于此询问线段右端点的限制线段加到树状数组中(在左端点+1),当区间和为0时可以满足条件,不为0则不能打出。

    #include<queue>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cmath>
    using namespace std;
    const int maxm=1e5+7;
    int n,k,q;
    int f[maxm],bian[maxm],dian[maxm],maxx[maxm],minn[maxm];
    int c[maxm];
    bool ans[maxm];
    int find(int x)
    {
      if(x!=f[x])
      f[x]=find(f[x]);
      return f[x]; 
    }
    int lowbit(int x)
    {
     return x&(-x);
    }
    void add(int x)
    {
     for(;x<=n;x+=lowbit(x))
     c[x]+=1;  
    }
    int ask(int x)
    {
     int ans=0;
     for(;x;x-=lowbit(x))
     ans+=c[x];
     return ans;   
    }
    struct node
    {
      int l,r,id;
      bool operator <(const node &s) const
      {
       return r<s.r;
      }
    }qwq[maxm],qaq[maxm];
    int main()
    {
     scanf("%d%d",&n,&k);
     for(int i=1;i<=n;i++)
     {
       f[i]=i;
       bian[i]=0;
       dian[i]=1;
       maxx[i]=i;
       minn[i]=i;
     }
     for(int i=1;i<=k;i++)
     {
      int x,y;
      scanf("%d%d",&x,&y);
      int fx=find(x);
      int fy=find(y);
      if(fx==fy)
      {
        bian[fx]++;
        continue;
      }
      if(fx!=fy)
      {
        f[fx]=fy;
        dian[fy]+=dian[fx];
        bian[fy]+=bian[fx]+1;
        dian[fx]=bian[fx]=0;
        maxx[fy]=max(maxx[fy],maxx[fx]);
        minn[fy]=min(minn[fy],minn[fx]);
      }
     }
     int tot=0;
     for(int i=1;i<=n;i++)
     {
       if(dian[i]==bian[i]+1)//一个点也是一棵树
       {
         qwq[++tot].l=minn[i];
         qwq[tot].r=maxx[i];
       }
     }
     scanf("%d",&q);
     for(int i=1;i<=q;i++)
     {
      int x,y;
      scanf("%d%d",&x,&y);
      qaq[i].l=x,qaq[i].r=y,qaq[i].id=i;
     }
     sort(qwq+1,qwq+tot+1);
     sort(qaq+1,qaq+q+1);
     int top=1;
     for(int i=1;i<=q;i++)
     {
      while(top<=tot&&qwq[top].r<=qaq[i].r)
      {
       add(qwq[top].l);
       top++;
      }
      if(ask(qaq[i].r)-ask(qaq[i].l-1))//有完整线段
      ans[qaq[i].id]=1;
     }
     for(int i=1;i<=q;i++)
     {
      if(ans[i])
      printf("No
    ");
      else
      printf("Yes
    "); 
     }
     return 0; 
    }
    
  • 相关阅读:
    阿里云ECS linux通过rinetd 端口转发来访问内网服务
    阿里云ECS linux通过iptables 配置SNAT代理网关,实现局域网上网
    适用于CentOS6.x系统的15项优化脚本
    ELK学习笔记
    MAC OSX环境下cordova+Ionic的安装配置
    Windows下 VM12虚拟机安装OS X 10.11 和VM TOOLS
    cordova 下载更新
    android adb常用命令
    ionic实现双击返回键退出功能
    ionic ngCordova插件安装
  • 原文地址:https://www.cnblogs.com/lihan123/p/11764764.html
Copyright © 2020-2023  润新知