zoukankan      html  css  js  c++  java
  • [SDOI2010]所驼门王的宝藏

    https://www.zybuluo.com/ysner/note/1250991

    题面

    有一个(n*m)的网格图,其中有(tot)个有门+宝藏的网格。这些门可以传送,且分为三类:

    • 门一:可到同行的任意一格
    • 门二:可到同列的任意一格
    • 门三:可到相邻的八格。

    从任意点出发和终止,最多能经过多少有宝藏的网格。

    • (totleq10^5,n,mleq10^6)

    解析

    首先可以考虑到的一个问题是,建边不能达到(O(n^2))
    然而,如果门一都在同行,门二都在同列,就可以达到。
    考虑把同行的门一、同列的门二用环连起来
    这样效果等价(强连通),建边复杂度降到(O(n))
    然后再暴力连同行同列剩下的门(用环中的一点)和门三连的有宝藏网格即可。

    这样弄完后,缩点+拓扑排序后跑最长路即可。(边权为联通块大小)

    然而细节非常容易出锅:
    1、如果(vector)中无值,访问(front())(back())(RE)
    (其实最好把它当一般数组用)
    2、(tarjan)不需要判(v!=fa)
    3、如果有两张图,且把(e)(e1)搞混,就会莫名(TLE)
    4、如果使用(unordered\_map)判重结构体,需要重载(==)运算符并手写(hash)函数。

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #include<vector>
    #include<tr1/unordered_map>
    #define ll long long
    #define re register
    #define il inline
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    #define fp(i,a,b) for(re int i=a;i<=b;i++)
    #define fq(i,a,b) for(re int i=a;i>=b;i--)
    using namespace std;
    const int N=1e5+100;
    struct Edge{int to,nxt;}e[N*50];
    struct node{int x,y,id;bool operator < (const node &o) const {return (x<o.x)||(x==o.x&&y<o.y);}}a[N];
    struct nnode{int x,y;bool operator == (const nnode &o) const {return x==o.x&&y==o.y;}}p[N*10];
    struct Hash{
      std::size_t operator () (const nnode &o) const{return o.x*N*10+o.y;};
    };
    int n,m,tot,h[N],cnt,fx[9]={0,1,-1,0,0,1,-1,1,-1},fy[9]={0,0,0,1,-1,1,-1,-1,1},low[N],dfn[N],st[N],tt,tim,sz[N],scc,bl[N],dis[N],T,in[N],ans,tmp[N];
    bool vis[N];
    vector<int>stan[N*10],stam[N*10];
    queue<int>Q;
    std::tr1::unordered_map<nnode,int,Hash>mp;
    il void add(re int u,re int v){e[++cnt]=(Edge){v,h[u]};h[u]=cnt;}
    il int gi()
    {
        re int x=0,t=1;
        re char ch=getchar();
        while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
        if(ch=='-') t=-1,ch=getchar();
        while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
        return x*t;
    }
    il void tarjan(re int u)
    {
      low[u]=dfn[u]=++tim;vis[u]=1;st[++tt]=u;
      re int v;
      for(re int i=h[u];i+1;i=e[i].nxt)
        {
          v=e[i].to;
          if(!dfn[v]) tarjan(v),low[u]=min(low[u],low[v]);
          else if(vis[v]) low[u]=min(low[u],dfn[v]);
        }
      if(low[u]==dfn[u])
        {
          ++scc;
          do{
        v=st[tt];vis[v]=0;bl[v]=scc;sz[scc]++;tt--;
          }
          while(v!=u);
        }
    }
    int main()
    {
      memset(h,-1,sizeof(h));
      tot=gi();n=gi();m=gi();
      fp(i,1,tot) a[i].x=gi(),a[i].y=gi(),a[i].id=gi(),mp[(nnode){a[i].x,a[i].y}]=i;
      fp(i,1,tot)
        {
          stan[a[i].x].push_back(i);
          stam[a[i].y].push_back(i);
          if(a[i].id==3)
          fp(j,1,8)
            {
              re int xx=a[i].x+fx[j],yy=a[i].y+fy[j];
              if(xx<1&&xx>n&&yy<1&&yy>m) continue;
              if(mp[(nnode){xx,yy}]) add(i,mp[(nnode){xx,yy}]);
            }
        }
      fp(i,1,n)
      {
        tt=0;
        for(re int j=0;j<stan[i].size();j++) 
          if(a[stan[i][j]].id==1) tmp[++tt]=stan[i][j];
        fp(j,1,tt-1) add(tmp[j],tmp[j+1]);add(tmp[tt],tmp[1]);
        for(re int j=0;j<stan[i].size();j++) 
          if(a[stan[i][j]].id!=1&&tt) add(tmp[1],stan[i][j]);
      }
      fp(i,1,m)
      {
        tt=0;
        for(re int j=0;j<stam[i].size();j++) 
          if(a[stam[i][j]].id==2) tmp[++tt]=stam[i][j];
        fp(j,1,tt-1) add(tmp[j],tmp[j+1]);add(tmp[tt],tmp[1]);
        for(re int j=0;j<stam[i].size();j++) 
          if(a[stam[i][j]].id!=2&&tt) add(tmp[1],stam[i][j]);
      }
      tt=0;
      fp(i,1,tot) if(!dfn[i]) tarjan(i);
      fp(u,1,tot)
        for(re int i=h[u];i+1;i=e[i].nxt)
          {
        re int v=e[i].to;
        if(bl[u]!=bl[v]) p[++T]=(nnode){bl[u],bl[v]};
          }
      memset(h,-1,sizeof(h));cnt=0;
      fp(i,1,T) add(p[i].x,p[i].y),in[p[i].y]++;
      fp(i,1,scc) if(!in[i]) Q.push(i);
      while(!Q.empty())
        {
          re int u=Q.front();Q.pop();dis[u]=max(dis[u],sz[u]);
          for(re int i=h[u];i+1;i=e[i].nxt)
        {
          re int v=e[i].to;--in[v];
          if(in[v]==0) Q.push(v);
          dis[v]=max(dis[v],dis[u]+sz[v]);
          ans=max(ans,dis[v]);
        }
       }
      printf("%d
    ",ans);
      return 0;
    }
    
  • 相关阅读:
    【数据库】Navicat Premium12远程连接MySQL数据库
    【Linux】一步一步学Linux——Centos7.5安装图解(08)
    【Tools】VMware虚拟机三种网络模式详解和操作
    【Linux】一步一步学Linux——VMware虚拟机三种网络模式详解(07)
    【Linux】一步一步学Linux——VMware Workstation 15 Pro安装图解教程(06)
    微信公众平台开发(25) 数据库操作
    微信公众平台开发(24) 自定义菜单功能开发
    微信公众平台开发(23) 聊天机器人功能开发
    微信公众平台开发(22) 翻译功能开发
    微信公众平台开发(21) 天气预报功能开发
  • 原文地址:https://www.cnblogs.com/yanshannan/p/9485106.html
Copyright © 2011-2022 走看看