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 是这个家族的领袖,外人也称其为“所驼门王”.所 驼门王毕生致力于维 ...
随机推荐
- SqlServer function 函数
SqlServer的数据库Tsql还是很强大,以此来纪念下表值函数的语法吧. -- ============================================= -- Author: & ...
- 2017年12月16日 ASP.NET基本用法
ASP.NET初级添加 利用css代码跟ASP.NET还有Javascript原生,LinQ来写增跟展示数据 首先介绍一个非常好用的控件,灵活并且循环展示数据库里面的数据 <asp:Repeat ...
- Linux中的叹号命令
在shell环境下操作,需要积累点快捷输入的小技巧: 最常用的技巧恐怕就是Tab自动补全以及上方向键来回退上几条历史命令了,这些对于csh,bash,ksh,zsh都适用. 最近还找到一种快速回退上一 ...
- 鼠标拖动改变DIV等网页元素的大小的最佳实践
1.初次实现 1.1 html代码 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" la ...
- python打开文件常见错误及解决办法
打开文件注意事项: 打开文件时需要,填写正确的路径,需要配置与文件相同的编码方式打开位机例如’utf-8‘,需要以特定 的模式打开文件 r, w,r+,w+,rb,wb,a, a+,ab等模式 f.o ...
- Bzoj1496: [NOI2006]千年虫
题面 传送门 Sol 左右可以分开搞 然后就是要形成一个类似梳子的东西 设\(f[0/1][i][j]\) \(0\)凹,\(1\)凸,\(i\)为行,可以滚一维,\(j\)为该行长度 \(f[0][ ...
- Python基础-socket编程
一.网络编程 自从互联网诞生以来,现在基本上所有的程序都是网络程序,很少有单机版的程序了. 计算机网络就是把各个计算机连接到一起,让网络中的计算机可以互相通信.网络编程就是如何在程序中实现两台计算机的 ...
- [转载]hive中order by,sort by, distribute by, cluster by作用以及用法
1. order by Hive中的order by跟传统的sql语言中的order by作用是一样的,会对查询的结果做一次全局排序,所以说,只有hive的sql中制定了order by所有的 ...
- 05_zookeeper的ACL
[ACL概述] ACL:access control Lists,权限控制. * 针对节点可以设置相关的读写等权限,目的是为了保障数据安全性. * 权限permissions可以指定不同的权限范围以及 ...
- Android 文件的可读可写
文件流形式的保存,获取: 设立文件的私有,可读,可写,公开: 效果图: /data/data中文件夹: 新建一个项目测试文件: 得到data/data,查看文件的特性: