题目大意:

有一个r*c的矩阵,上面有n个点有宝藏

每个有宝藏的点上都有传送门

传送门有三种:第一种可以传到该行任意一个有宝藏的点,第二种可以传到该列任意一个有宝藏的点,第三种可以传到周围的八连块上有宝藏的点

现在你可以在任意一个有宝藏的点开始,求你最多可以经过多少个不同的藏宝点

每个藏宝点可以多次进入,每个传送门可以多次使用

思路:

很容易可以看出这个矩阵并没有什么卵用

而此题的关键在于如何建图,建图所用数组见注释

建完之后,可以使用tarjan算法之一的求强连通分量

因为对于每个强连通分量,只要到达任意一个点,就可以到达其余所有点

然后我们缩点,把每个强连通分量都缩为一个点

再重新建图

这样图就会变成DAG,然后求一下最长链并统计每一个强连通分量内有几个点就好了

 #include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<vector>
#include<stack>
#include<set>
#include<map>
#define inf 2147483611
#define ll long long
#define MAXN 101001
using namespace std;
inline int read()
{
int x=,f=;
char ch;ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-;ch=getchar();}
while(isdigit(ch)) {x=x*+ch-'';ch=getchar();}
return x*f;
}
int dx[]={,,,-,-,-,,},dy[]={,,-,,,-,,-};//八连块用数组
map <int,int> m[*MAXN];//记录每个位置是否有藏宝点,因为数组开不下只能用map
vector <int> vr[*MAXN],vc[*MAXN];//记录每行每列所有藏宝点,用vector方便记录
int n,r,c;
int x[MAXN],y[MAXN];//记录每个点的横纵坐标
short t[MAXN];//记录每个点的传送门种类
int to[*MAXN],next[*MAXN],first[MAXN],cnt;//第一次图用邻接表
int to0[*MAXN],next0[*MAXN],first0[MAXN];//DAG第二次图用邻接表
int low[MAXN],dfn[MAXN],stp,scc,now,st[MAXN],top;//tarjan用数组
//scc记录一共有多少强连通分量,stp记录步数,st、top记录栈
int num[MAXN],blg[MAXN];//num记录每个强连通分量中有多少个点,blg记录每个点属于那个强连通分量
int deep[MAXN];//求最长链用,记录每个强连通分量能延伸的最长长度
int ans;
bool vis[MAXN];//第一次为tarjan用,第二次求最长链用
void add(int u,int v)//第一次建图
{
if(u==v) return ;
to[++cnt]=v,next[cnt]=first[u],first[u]=cnt;
}
void ADD(int u,int v) {to0[++cnt]=v,next0[cnt]=first0[u],first0[u]=cnt;}//第二次建图
void build()//第一次建图
{
int tmp,s;
for(int i=;i<=r;i++)//同一行的藏宝图
{
tmp=,s=vr[i].size();
for(int j=;j<s;j++) if(t[vr[i][j]]==) {tmp=vr[i][j];break;}
for(int j=;j<s;j++)
{
add(tmp,vr[i][j]);
if(t[vr[i][j]]==) add(vr[i][j],tmp);//不用连所有边,只需要这样就可以满足要求
}
}
for(int i=;i<=c;i++)//同一列,方法同上
{
tmp=,s=vc[i].size();
for(int j=;j<s;j++) if(t[vc[i][j]]==) {tmp=vc[i][j];break;}
for(int j=;j<s;j++)
{
add(tmp,vc[i][j]);
if(t[vc[i][j]]==) add(vc[i][j],tmp);
}
}
for(int i=;i<=n;i++)//八连块
if(t[i]==)
for(int j=;j<;j++) if(m[x[i]+dx[j]][y[i]+dy[j]]) add(i,m[x[i]+dx[j]][y[i]+dy[j]]);
}
void tarjan(int x)//tarjan求强连通分量
{
low[x]=dfn[x]=++stp;
st[++top]=x;vis[x]=;
for(int i=first[x];i;i=next[i])
if(!dfn[to[i]])
{tarjan(to[i]);low[x]=min(low[x],low[to[i]]);}//在栈外且未被访问过
else if(vis[to[i]]) low[x]=min(low[x],dfn[to[i]]);//在栈内
if(low[x]==dfn[x])
{
scc++;now=;
while(now!=x)
{
now=st[top--];vis[now]=;
blg[now]=scc;num[scc]++;
}
}
}
void BUILD()//第二次建图
{
for(int i=;i<=n;i++)
for(int j=first[i];j;j=next[j])
if(blg[i]!=blg[to[j]]) ADD(blg[i],blg[to[j]]);
}
void dp(int x)//求最长链
{
vis[x]=;
for(int i=first0[x];i;i=next0[i])
{
if(!vis[to0[i]]) dp(to0[i]);
deep[x]=max(deep[x],deep[to0[i]]);//延伸
}
deep[x]+=num[x];
ans=max(ans,deep[x]);
}
int main()
{
n=read(),r=read(),c=read();
for(int i=;i<=n;i++)
{
x[i]=read(),y[i]=read(),t[i]=read();
m[x[i]][y[i]]=i;
vr[x[i]].push_back(i);
vc[y[i]].push_back(i);
}
build();
for(int i=;i<=n;i++)
if(!dfn[i]) tarjan(i);
cnt=;
BUILD();
for(int i=;i<=scc;i++)
if(!vis[i]) dp(i);
printf("%d",ans);
}

bzoj 1924 所驼门王的宝藏的更多相关文章

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

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

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

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

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

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

  4. 「BZOJ1924」「SDOI2010」 所驼门王的宝藏 tarjan + dp(DAG 最长路)

    「BZOJ1924」[SDOI2010] 所驼门王的宝藏 tarjan + dp(DAG 最长路) -------------------------------------------------- ...

  5. 8.18 NOIP模拟测试25(B) 字符串+乌鸦喝水+所驼门王的宝藏

    T1 字符串 卡特兰数 设1为向(1,1)走,0为向(1,-1)走,限制就是不能超过$y=0$这条线,题意转化为从(0,0)出发,走到(n+m,n-m)且不越过$y=0$,然后就裸的卡特兰数,$ans ...

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

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

  7. noip模拟5[string·matrix·big·所驼门王的宝藏]

    怎么说呢这一场考得还算可以呢 拿了120pts,主要是最后一个题灵光开窍,想起来是tarjan,然后勉勉强强拿了40pts,本来是可以拿满分的,害 没事考完了就要反思 这场考试我心态超好,从第一个题开 ...

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

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

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

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

随机推荐

  1. 性能测试培训day1

    测试本质: 1构造测试数据和期望结果 2执行 3验证 自动化测试: 写完代码,单元测试测代码逻辑,单元测试搞清楚代码逻辑就行了(白盒测试)先静态,运行前用工具扫描BUG例如(a==11写成a=11), ...

  2. 创建Tensor

    目录 创建Tensor numpy, list numpy list zeros, ones, fill zeros ones fill random 打乱idx后,a和b的索引不变 constant ...

  3. 原生JS版和jQuery 版实现文件上传功能

    <!doctype html> <html lang="zh"> <head> <meta charset="utf-8&quo ...

  4. HDU 1564 找规律博弈

    题目大意是: 从n*n的方格角落的一个起点出发,每次移到上下左右一个未曾到达过的位置,谁不能走了谁就输了 想了好久都想不出,看了大神的题解 Orz了 果然博弈不是脑残的游戏啊... 这里从起点出发,将 ...

  5. cf 55D 数位dp 好题

    /* 刚开始我考虑0的情况,想将他剔除就将lcmn设为-1,这样还要判断0和lcmn是-1的情况很麻烦而且但是一直出错 后来觉得不用管0的情况就行了,可以认为符合. 解:将lcmn离散化,因为1-9的 ...

  6. bzoj 1005 [HNOI2008] 明明的烦恼 (prufer编码)

    [HNOI2008]明明的烦恼 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 5907  Solved: 2305[Submit][Status][Di ...

  7. SQLAlchemy(1):单表操作

    SQLAlchemy 是一个 ORM框架:类对应表,类中的字段对应表中的列,类的对象对应表的一条记录:作用:帮助我们使用类和对象快速实现数据库操作操作数据库的方式: 1. 原生SQL - pymysq ...

  8. Bzoj3038 上帝造题的七分钟2 并查集

    Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 1135  Solved: 509 Description XLk觉得<上帝造题的七分钟>不太 ...

  9. codevs——1006 等差数列

    1006 等差数列  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题解  查看运行结果     题目描述 Description 给定n(1<=n< ...

  10. 洛谷 P1023 税收与补贴问题

    P1023 税收与补贴问题 题目背景 每样商品的价格越低,其销量就会相应增大.现已知某种商品的成本及其在若干价位上的销量(产品不会低于成本销售),并假设相邻价位间销量的变化是线性的且在价格高于给定的最 ...