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

10 7 7
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

9

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]所驼门王的宝藏(强连通分量,拓扑排序)的更多相关文章

  1. 【题解】SDOI2010所驼门王的宝藏(强连通分量+优化建图)

    [题解]SDOI2010所驼门王的宝藏(强连通分量+优化建图) 最开始我想写线段树优化建图的说,数据结构学傻了233 虽然矩阵很大,但是没什么用,真正有用的是那些关键点 考虑关键点的类型: 横走型 竖 ...

  2. BZOJ 1924 所驼门王的宝藏(强连通分量缩点+DAG最长链)

    思路不是很难,因为宝藏只会在给出的n个点内有,于是只需要在这n个点里面连边,一个点如果能到达另一个点则连一条有向边, 这样用强连通分量缩点后答案就是DAG的最长链. 问题在于暴力建图是O(n^2)的, ...

  3. BZOJ1924 [Sdoi2010]所驼门王的宝藏 【建图 + tarjan】

    题目 输入格式 第一行给出三个正整数 N, R, C. 以下 N 行,每行给出一扇传送门的信息,包含三个正整数xi, yi, Ti,表示该传送门设在位于第 xi行第yi列的藏宝宫室,类型为 Ti.Ti ...

  4. bzoj1924: [Sdoi2010]所驼门王的宝藏

    陈年老题又来水一发啊啊啊 构图狗了一点,然后其实强连通缩点dij找最长路就没了. 没调出来有点气,直接打了第9个点的表.... 来逛blog的你教教我呗 #include<cstdio> ...

  5. 【BZOJ-1924】所驼门王的宝藏 Tarjan缩点(+拓扑排序) + 拓扑图DP

    1924: [Sdoi2010]所驼门王的宝藏 Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 787  Solved: 318[Submit][Stat ...

  6. [BZOJ 1924][Sdoi2010]所驼门王的宝藏

    1924: [Sdoi2010]所驼门王的宝藏 Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 1285  Solved: 574[Submit][Sta ...

  7. [SDOI2010]所驼门王的宝藏

    题目描述 在宽广的非洲荒漠中,生活着一群勤劳勇敢的羊驼家族.被族人恭称为"先知"的Alpaca L. Sotomon是这个家族的领袖,外人也称其为"所驼门王". ...

  8. [LuoguP2403][SDOI2010]所驼门王的宝藏

    题目描述 在宽广的非洲荒漠中,生活着一群勤劳勇敢的羊驼家族.被族人恭称为"先知"的Alpaca L. Sotomon是这个家族的领袖,外人也称其为"所驼门王". ...

  9. BZOJ 1924: [Sdoi2010]所驼门王的宝藏 【tarjan】

    Description 在宽广的非洲荒漠中,生活着一群勤劳勇敢的羊驼家族.被族人恭称为“先 知”的Alpaca L. Sotomon 是这个家族的领袖,外人也称其为“所驼门王”.所 驼门王毕生致力于维 ...

随机推荐

  1. .netCore2.0 依赖注入

    依赖注入(ID)是一种实现对象及其合作者或者依赖想之间松散耦合的技术对于传统的方法来说,获取类的方法通常用new如下 public class DIController : Controller { ...

  2. 利用SqlDataAdapter进行分页

    利用SqlDataAdapter进行记录分页 说到分页,很多地方都会用到,不管是windows程序还是web程序,为什么要进行分页?很简单,如果BlueIdea BBS帖子列表不分页的话,几十万条记录 ...

  3. Java - 多线程中的不变性问题

    这篇记录一下保证并发安全性的策略之——不变性. (注意:是Immutable,不是Invariant!) 将一连串行为组织为一个原子操作以保证不变性条件,或者使用同步机制保证可见性,以防止读到失效数据 ...

  4. 如何删除eclipse中已经保存的svn密码

    一.打开eclipse--->点击Window--->点击Perference,打开eclipse配置,输入svn,然后点击svn,找到下方svn接口,查看下svn是什么类型的接口,如果是 ...

  5. servlet开发(四)之ServletContext

    接上一篇. 2.3.4 利用ServletContext对象读取资源文件 比如我们要读取web项目中的配置文件. 项目目录结构如下: 使用ServletContext对象读取资源文件的示例代码如下: ...

  6. android 动态库死机调试方法 .

    原地址:http://blog.csdn.net/andyhuabing/article/details/7074979 这两种方法都不是我发明了,都是网上一些高手公共出来的调试方法,无奈找不到出处的 ...

  7. 爬取地图列表并下载-node.js

    var fs = require('fs'); var request = require('request'); var cheerio = require('cheerio'); var url ...

  8. mybatis向数据库插入数据 (传入的是一个实体类)

    /** * 插入用户信息 user为实体类 * @param user */ public int insert( User user); //实体类不用@param标注 //mybatis的xml文 ...

  9. javascript图片预加载

    图片预加载是非常常见的一个功能,PC和移动端都会用到,尤其是在移动端,只要涉及到较多图片的加载都会用到该技术.下面是移动端用到的,引入了zepto. <!DOCTYPE html> < ...

  10. php注册

    <?php var_dump($_GET);//打印出对象的数据类型//链接数据库$link = @mysql_connect('localhost','root','root');#选择数据库 ...