Luogu P2403 [SDOI2010]所驼门王的宝藏

比较显然的缩点+拓扑排序题,只不过要建虚点优化建边

首先我们发现在一个SCC里的点都是可以一起对答案产生贡献的,因此先缩成DAG,然后拓扑找最长链。

但是我们发现这题最坏情况下边数会达到恐怖的(O(n^2)),因此我们可以对于每种门进行讨论:

  • 横天门:将该点向这个点坐在的格子的横坐标建立虚点并连边
  • 纵寰门:将该点向这个点坐在的格子的纵坐标建立虚点并连边
  • ZY门:暴力八个方向直接连边即可,(拿map存坐标吧,不会T的)

然后每个点对应横纵坐标的虚点都向这个点连边,这样就可以处理同行/列的情况。

不过这样写Tarjan就要注意常数问题了(点数边数(10000000+)),手动卡常松松松

CODE

#include<cstdio>
#include<cctype>
#include<map>
#include<utility>
#include<cstring>
#define mp make_pair
using namespace std;
const int N=100005,R=1000005;
const int fx[8]={0,1,0,-1,1,1,-1,-1},fy[8]={1,0,-1,0,1,-1,1,-1};
map <pair<int,int>,int> h;
int n,r,c,cnt,head[N+(R<<1)],nhead[N+(R<<1)],dfn[N+(R<<1)],stack[N+(R<<1)],low[N+(R<<1)],s[N+(R<<1)],tot,scc,top,col[N+(R<<1)],ru[N+(R<<1)],d[N+(R<<1)],q[N+(R<<1)];
bool vis[N+(R<<1)];
struct data
{
    int x,y,opt;
}a[N];
struct edge
{
    int to,next;
}e[N<<3],ne[N<<3];
inline char tc(void)
{
    static char fl[100000],*A=fl,*B=fl;
    return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(int &x)
{
    x=0; char ch; while (!isdigit(ch=tc()));
    while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc()));
}
inline void add(int x,int y)
{
    e[++cnt].to=y; e[cnt].next=head[x]; head[x]=cnt;
}
inline void nadd(int x,int y)
{
    ne[++cnt].to=y; ne[cnt].next=nhead[x]; nhead[x]=cnt;
}
inline void build(int x,int y,int id)
{
    for (register int i=0;i<8;++i)
    {
        int xx=x+fx[i],yy=y+fy[i];
        if (xx>0&&xx<=r&&yy>0&&yy<=c&&h[mp(xx,yy)]) add(id,h[mp(xx,yy)]);
    }
}
inline void miner(int &x,int y)
{
    if (y<x) x=y;
}
inline void maxer(int &x,int y)
{
    if (y>x) x=y;
}
inline void Tarjan(int now)
{
    dfn[now]=low[now]=++tot; stack[++top]=now; vis[now]=1;
    for (register int i=head[now];~i;i=e[i].next)
    if (!dfn[e[i].to]) Tarjan(e[i].to),miner(low[now],low[e[i].to]);
    else if (vis[e[i].to]) miner(low[now],dfn[e[i].to]);
    if (dfn[now]==low[now])
    {
        col[now]=++scc; vis[now]=0; s[scc]=(now<=n);
        while (stack[top]!=now)
        col[stack[top]]=scc,vis[stack[top]]=0,s[scc]+=(stack[top--]<=n); --top;
    }
}
inline int top_sort(void)
{
    register int i,H=0,T=0; int ans=0;
    for (i=1;i<=scc;++i) if (!ru[i]) q[++T]=i,d[i]=s[i];
    while (H<T)
    {
        int now=q[++H]; maxer(ans,d[now]);
        for (i=nhead[now];~i;i=ne[i].next)
        {
            maxer(d[ne[i].to],d[now]+s[ne[i].to]);
            if (!(--ru[ne[i].to])) q[++T]=ne[i].to;
        }
    }
    return ans;
}
int main()
{
    //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
    register int i,j; read(n); read(r); read(c);
    memset(head,-1,sizeof(head)); memset(nhead,-1,sizeof(nhead));
    for (i=1;i<=n;++i)
    {
        read(a[i].x); read(a[i].y); read(a[i].opt);
        switch (a[i].opt)
        {
            case 1:add(i,n+a[i].x);break;
            case 2:add(i,n+r+a[i].y);break;
        }
        add(n+a[i].x,i); add(n+r+a[i].y,i); h[mp(a[i].x,a[i].y)]=i;
    }
    for (i=1;i<=n;++i) if (a[i].opt==3) build(a[i].x,a[i].y,i);
    for (i=1;i<=n+r+c;++i) if (!dfn[i]) Tarjan(i);
    for (cnt=0,i=1;i<=n+r+c;++i)
    for (j=head[i];~j;j=e[j].next)
    if (col[i]!=col[e[j].to]) nadd(col[e[j].to],col[i]),++ru[col[i]];
    return printf("%d",top_sort()),0;
}
原文地址:https://www.cnblogs.com/cjjsb/p/9600907.html