BZOJ1924:[SDOI2010]所驼门王的宝藏(强连通分量,拓扑排序)
Description

Input
第一行给出三个正整数 N, R, C。 以下 N 行,每行给出一扇传送门的信息,包含三个正整数xi, yi, Ti,表示该传送门设在位于第 xi行第yi列的藏宝宫室,类型为 Ti。Ti是一个1~3间的整数, 1表示可以传送到第 xi行任意一列的“横天门”,2表示可以传送到任意一行第 yi列的“纵寰门”,3表示可以传送到周围 8格宫室的“八方门”。 保证 1≤xi≤R,1≤yi≤C,所有的传送门位置互不相同。
Output
只有一个正整数,表示你确定的路线所经过不同藏宝宫室的最大数目。
Sample Input
2 2 1
2 4 2
1 7 2
2 7 3
4 2 2
4 4 1
6 7 3
7 7 1
7 5 2
5 2 1
Sample Output
HINT
N<=100000, R<=100000, C<=100000
Solution
一开始的正解的想法让我以为边数太多然后叉掉了……其实是可以过的……
很容易可以想到做法就是门和门之间连边,然后tarjan缩个点再拓扑排序跑个最长路就完事了。不过直接连边$n^2$肯定会GG。
对于同一行的门来说,横门间显然可以相互传送,只需要选定一个横门,然后向这一行的其他横门连双向边,向这一行的其他门连单向边,这样就可以保证缩点后横门在一个强连通分量里了。列同理。
Code
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
#include<map>
#define N (100009)
using namespace std; struct Node{int x,y,t,id;}a[N];
struct Edge{int to,next;}edge[N*];
int n,m,r,c,e1[N*],e2[N*],Ind[N],dp[N];
int head[N],num_edge;
int Dfn[N],Low[N],stack[N],ID[N],Num[N];
int top,id_num,dfs_num;
int dx[]={,,,,,,-,-,-},dy[]={,,-,,,-,,,-};
vector<int>Line[N*],List[N*];
map<int,int>Map[N*];
queue<int>q;
bool vis[N]; void add(int u,int v)
{
edge[++num_edge].to=v;
edge[num_edge].next=head[u];
head[u]=num_edge;
if (!m) e1[num_edge]=u,e2[num_edge]=v;
} void Tarjan(int x)
{
Dfn[x]=Low[x]=++dfs_num;
stack[++top]=x; vis[x]=true;
for (int i=head[x]; i; i=edge[i].next)
if (!Dfn[edge[i].to])
Tarjan(edge[i].to),Low[x]=min(Low[x],Low[edge[i].to]);
else if (vis[edge[i].to])
Low[x]=min(Low[x],Dfn[edge[i].to]);
if (Low[x]==Dfn[x])
{
vis[x]=false; ID[x]=++id_num; Num[id_num]++;
while (stack[top]!=x)
{
vis[stack[top]]=false;
Num[id_num]++;
ID[stack[top--]]=id_num;
}
top--;
}
} void Add()
{
for (int i=; i<=r; ++i)
{
int x=,sz=Line[i].size();
for (int j=; j<sz; ++j)
if (a[Line[i][j]].t==){x=Line[i][j]; break;}
if (!x) continue;
for (int j=; j<sz; ++j)
if (Line[i][j]!=x)
{
add(x,Line[i][j]);
if (a[Line[i][j]].t==) add(Line[i][j],x);
}
}
for (int i=; i<=c; ++i)
{
int x=,sz=List[i].size();
for (int j=; j<sz; ++j)
if (a[List[i][j]].t==){x=List[i][j]; break;}
if (!x) continue;
for (int j=; j<sz; ++j)
if (List[i][j]!=x)
{
add(x,List[i][j]);
if (a[List[i][j]].t==) add(List[i][j],x);
}
}
for (int i=; i<=n; ++i)
if (a[i].t==)
{
int x=a[i].x,y=a[i].y;
for (int j=; j<=; ++j)
{
int t=Map[x+dx[j]][y+dy[j]];
if (t) add(i,t);
}
}
} void Toposort()
{
int ans=;
for (int i=; i<=id_num; ++i) ans=max(ans,Num[i]);
for (int i=; i<=id_num; ++i) if (!Ind[i]) q.push(i),dp[i]=Num[i];
while (!q.empty())
{
int x=q.front(); q.pop();
for (int i=head[x]; i; i=edge[i].next)
{
int y=edge[i].to; Ind[y]--;
if(!Ind[y]) q.push(y);
dp[y]=max(dp[y],dp[x]+Num[y]);
ans=max(ans,dp[y]);
}
}
printf("%d\n",ans);
} int main()
{
scanf("%d%d%d",&n,&r,&c);
for (int i=; i<=n; ++i)
{
scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].t);
Line[a[i].x].push_back(i);
List[a[i].y].push_back(i);
Map[a[i].x][a[i].y]=i;
}
Add();
for (int i=; i<=n; ++i)
if (!Dfn[i]) Tarjan(i); memset(head,,sizeof(head));
m=num_edge; num_edge=;
for (int i=; i<=m; ++i)
if (ID[e1[i]]!=ID[e2[i]])
add(ID[e1[i]],ID[e2[i]]),Ind[ID[e2[i]]]++;
Toposort();
}
BZOJ1924:[SDOI2010]所驼门王的宝藏(强连通分量,拓扑排序)的更多相关文章
- 【题解】SDOI2010所驼门王的宝藏(强连通分量+优化建图)
[题解]SDOI2010所驼门王的宝藏(强连通分量+优化建图) 最开始我想写线段树优化建图的说,数据结构学傻了233 虽然矩阵很大,但是没什么用,真正有用的是那些关键点 考虑关键点的类型: 横走型 竖 ...
- BZOJ 1924 所驼门王的宝藏(强连通分量缩点+DAG最长链)
思路不是很难,因为宝藏只会在给出的n个点内有,于是只需要在这n个点里面连边,一个点如果能到达另一个点则连一条有向边, 这样用强连通分量缩点后答案就是DAG的最长链. 问题在于暴力建图是O(n^2)的, ...
- BZOJ1924 [Sdoi2010]所驼门王的宝藏 【建图 + tarjan】
题目 输入格式 第一行给出三个正整数 N, R, C. 以下 N 行,每行给出一扇传送门的信息,包含三个正整数xi, yi, Ti,表示该传送门设在位于第 xi行第yi列的藏宝宫室,类型为 Ti.Ti ...
- bzoj1924: [Sdoi2010]所驼门王的宝藏
陈年老题又来水一发啊啊啊 构图狗了一点,然后其实强连通缩点dij找最长路就没了. 没调出来有点气,直接打了第9个点的表.... 来逛blog的你教教我呗 #include<cstdio> ...
- 【BZOJ-1924】所驼门王的宝藏 Tarjan缩点(+拓扑排序) + 拓扑图DP
1924: [Sdoi2010]所驼门王的宝藏 Time Limit: 5 Sec Memory Limit: 128 MBSubmit: 787 Solved: 318[Submit][Stat ...
- [BZOJ 1924][Sdoi2010]所驼门王的宝藏
1924: [Sdoi2010]所驼门王的宝藏 Time Limit: 5 Sec Memory Limit: 128 MBSubmit: 1285 Solved: 574[Submit][Sta ...
- [SDOI2010]所驼门王的宝藏
题目描述 在宽广的非洲荒漠中,生活着一群勤劳勇敢的羊驼家族.被族人恭称为"先知"的Alpaca L. Sotomon是这个家族的领袖,外人也称其为"所驼门王". ...
- [LuoguP2403][SDOI2010]所驼门王的宝藏
题目描述 在宽广的非洲荒漠中,生活着一群勤劳勇敢的羊驼家族.被族人恭称为"先知"的Alpaca L. Sotomon是这个家族的领袖,外人也称其为"所驼门王". ...
- BZOJ 1924: [Sdoi2010]所驼门王的宝藏 【tarjan】
Description 在宽广的非洲荒漠中,生活着一群勤劳勇敢的羊驼家族.被族人恭称为“先 知”的Alpaca L. Sotomon 是这个家族的领袖,外人也称其为“所驼门王”.所 驼门王毕生致力于维 ...
随机推荐
- vue2.0的虚拟DOM渲染
1.为什么需要虚拟DOM 前面我们从零开始写了一个简单的类Vue框架(文章链接),其中的模板解析和渲染是通过Compile函数来完成的,采用了文档碎片代替了直接对页面中DOM元素的操作,在完成数据的更 ...
- ios下虚拟键盘出现"搜索"字样
最近在开发过程中,发现用户输入想要检索的内容,弹出虚拟键盘,在安卓机上虚拟键盘最右下角会有‘搜索’字样,而ios上虚拟键盘最右下角只有‘换行’字样, 这样用户体验就会大打折扣. 安卓机上虚拟键盘 io ...
- springboot+mybatis+thymeleaf+docker构建的个人站点开源项目(集成了个人主页、个人作品、个人博客)
前言 My Site 主要功能有:个人首页.个人作品.个人博客为一体的站点,网站的文章和作品均由markdown进行编写,可以满足你的基本需求.如果觉得这个项目不错,请为它点赞支持. 项目架构 JDK ...
- 互联网轻量级框架SSM-查缺补漏第六天【级联+延迟加载特辑】
简言:本来这是昨天看的,但是因为想好好写一下[级联]这个东西,所以就看完之后今天来整理一下. 级联 1. 什么是级联 级联是一个数据库实体的概念.比如教师就需要存在学生与之对应,这样就有教师学生表,一 ...
- flask_restful的使用方法
一 安装: pip install flask_restrul 二 初始化并注册路由 # run.py from flask_restful import Api ... api = Api(app) ...
- 打印thinkphp中的sql语句
var_dump($repair->fetchSql(true)->where(array('cuername' =>$cuername))->order('applytime ...
- nodejs的socket.io学习笔记
socket.io学习笔记 1.服务器信息传输: 2.不分组,数据传输: 3.分组数据传输: 4.Socket.io难点大放送(暂时没有搞定): 服务器信息传输 1. // send to curre ...
- Web前端面试指导(二十):JavaScript中如何翻转一个字符串?
题目点评 字符串作在程序中是非常常见的,因为程序中绝大部分的数据都可以当作字符串来处理.需要对字符的处理方法比较熟悉,在回答的时候尽量能够说出多种解决方法更好! 字符串翻转的方法 1)使用字符串函数 ...
- mysqlcppconn之ConnectOptionsMap的使用
由来 继上一篇文章, 发现之前写的一篇文章中断线重连部分是错误的, 也是现在翻阅了源码才知道 想要自动重连, 必须使用ConnectOptionsMap才可以 但由于官方代码没有做好导出部分的处理, ...
- 利用canvas来绘制一个会动的图画,欢迎指教
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...