省选专练SDOI2010所驼门王的宝藏

这是一个奇怪的题

首先,其思路和APIO2009-3掠夺计划相比难得多,数据变大了啊。

于是两两建边不可行,考虑用拉链判重。

从横天门或纵寰门引出的边可能特别多。在极端情况下,10^5个横天门在同一行里出现,这样时空复杂度都是无法承受的。考虑这一点进行优化:由于在同一行的横天门一定属于同一个强连通分量,所以在建边时,只需要对在同一行的横天门构建出一个环即可,不需要两两进行连边。而此行内的其他宫室,只需要从这个环中的任意一点向这个宫室连边即可。对于纵寰门也是一样。

然后缩了点想干嘛就干嘛top还是SPFA都可以

#include<iostream>
#include<cstdio>
#include<stack>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<map>
using namespace std;
inline void read(int &x){
    int f=1;
    x=0;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while(ch<='9'&&ch>='0'){
        x=x*10+ch-'0';
        ch=getchar();
    }
    x*=f;
}
int dx[]={0,1,0,-1,1,1,-1,-1};
int dy[]={1,0,-1,0,-1,1,-1,1};
int n,r,c;

struct Front_star{
    int u,v,w,nxt;
}edge[5000000],e[5000000],ee[5000000];
int cnt=0;
int first[500000]={0};
int head[500000]={0};
struct Node{
    int x,y,t;
}pre[2000007]/*first array*/,nxt[2000007],a[2000007];
void addedge(int u,int v,int w){
    cnt++;
    e[cnt].u=u;
    e[cnt].v=v;
    e[cnt].w=w;
    e[cnt].nxt=first[u];
    first[u]=cnt;
}
void adde(int u,int v,int w){
    cnt++;
    ee[cnt].u=u;
    ee[cnt].v=v;
    ee[cnt].w=w;
    ee[cnt].nxt=head[u];
    head[u]=cnt;
}
void add(){
    for(int i=1;i<=n;i++){
        if(a[i].t==1){
            for(int j=pre[a[i].x].x;j;j=nxt[j].x){
                if(i==j){
                    continue;
                }
                addedge(i,j,1);
            }
        }
        if(a[i].t==2){
            for(int j=pre[a[i].y].y;j;j=nxt[j].y){
                if(i==j){
                    continue;
                }
                addedge(i,j,1);
            }
        }
        if(a[i].t==3){
            for(int k=0;k<8;k++){
                int xx=a[i].x+dx[k];
                for(int j=pre[xx].x;j;j=nxt[j].x){
                    if(i==j)
                        continue;
                    if(abs(a[j].y-a[i].y)<=1)
                    addedge(i,j,1);
                } 
            }
        }
    }
}
int tot=0;
//--------------
int low[500000]={0};
int dfn[500000]={0};
int color[500000]={0};
int siz[500000]={0};
int inqueue[500000]={0};
int scc=0;
stack<int> S;
void tarjan(int u){
    tot++;
    low[u]=dfn[u]=tot;
    S.push(u);
    inqueue[u]=1;
    for(int i=first[u];i;i=e[i].nxt){
        int v=e[i].v;
        if(!dfn[v]){
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else{
            if(inqueue[v]){
                low[u]=min(low[u],dfn[v]);
            }
        }
    }
    if(low[u]==dfn[u]){
        int x;
        scc++;
        do{
            x=S.top();
            S.pop();
            color[x]=scc;
            siz[scc]++;
            inqueue[x]=0;
        }while(x!=u);
    }	
}
int rd[500001]={0};
int cd[500001]={0};
int dis[500001]={0};
void SPFA(){
    queue<int>q;
    for(int i=1;i<=scc;i++){
        if(rd[i]==0){
            q.push(i);
            dis[i]=siz[i];
        }
    }
    while(!q.empty()){
        int x=q.front();
        q.pop();
        for(int i=head[x];i;i=ee[i].nxt){
            int v=ee[i].v;
            if(rd[v]==0)
                continue;
            rd[v]--;
            if(dis[v]<dis[x]+siz[v]){
                dis[v]=dis[x]+siz[v];
            }
            if(!rd[v]){
                q.push(v);
            }
        }
    }
}
int main(){
    read(n);
    read(r);
    read(c);
    for(int i=1;i<=n;i++){
        int x,y,t;
        read(x);
        read(y);
        read(t);
        a[i].x=x;
        a[i].y=y;
        a[i].t=t;
        nxt[i].x=pre[x].x;
        pre[x].x=i;
        nxt[i].y=pre[y].y;
        pre[y].y=i;
    }
    add();
    for(int i=1;i<=n;i++){
        if(!dfn[i]){
            tarjan(i);
        }
    }
//	cnt=0;
//	memset(first,0,sizeof(first));
    for(int i=1;i<=n;i++){
        for(int j=first[i];j;j=e[j].nxt){
            int v=e[j].v;
            int u=i;
            if(color[u]!=color[v]){
                adde(color[u],color[v],1);
                rd[color[v]]++;
                cd[color[u]]++;
            }
        }
    }
//	for(int i=1;i<=scc;i++)
//		cout<<rd[i]<<" "<<siz[i]<<endl;
    SPFA();
    int ans=-1;
//	cout<<"4q382436939486724389279834"<<endl;
    for(int i=1;i<=scc;i++){
        ans=max(ans,dis[i]);
//		cout<<siz[i]<<" "<<cd[i]<<endl;
    }
    cout<<ans;
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值