点此看题面

大致题意: 一个由\(R*C\)间矩形宫室组成的宫殿中的\(N\)间宫室里埋藏着宝藏。由一间宫室到达另一间宫室只能通过传送门,且只有埋有宝藏的宫室才有传送门。传送门分为3种,分别可以到达同行的任一宫室(横天门)同列的任一宫室(纵寰门)以该宫室为中心周围8个的任一宫室(自 由 门)。现在你可以从任一宫室开始寻宝,并可以在任一宫室结束寻宝,请求出最多可获得的宝藏数目(每个宝藏只能获得一次)。

一个简单的想法

显然,我们可以将每个宫室与它能到达的宫室之间连一条边。由于可能会出现环,我们就需要用\(Tarjan\)来把环缩点,缩点的过程中要注意记录每个环上的宫室数目。

缩完点后,我们就可以从每个入度为1的点开始对图进行遍历,求出最多能走过的宫室数。而这个步骤可以用dfs轻松实现。

这样就好了吗?

不,还有一些细节。

小技巧优化

首先,我们要注意的是,直接把每个宫室与它能到达的宫室之间两两建边,建出的边的规模是\(O(N^2)\)的,而\(N≤100000\),这么多边我们存不下。虽然洛谷数据水,这样也能过。

这时就要用到一个小技巧:对于同一行的横天门,我们不需要将其两两之间连边,只要保证最后能够连成一个即可;而该行其他类型的门,也不需要将每一个横天门向其连边,只要让第一个出现的横天门向所有其他类型的门连边即可。同理,对于同一行的纵寰门,也可以进行同样的处理,让边数从\(O(n^2)\)降到了\(O(n)\)大大减少了边数。

还有,就算你进行了这样的操作,最后还是有可能会TLE,这时,我们可以发现,好像时间复杂度最大的就是最后的dfs遍历了。我们可以考虑用记忆化,用\(vist[i]\)来记录从缩点后编号为\(i\)的点出发,最多能得到的宝物数目即可。

这样,就可以AC了。

代码

#include<bits/stdc++.h>
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define LL long long
#define N 100000
using namespace std;
typedef pair<int,int> point;
int n,r,c,d=0,ee=0,nee=0,cnt=0,ans=0,top=0,lnk[N+5],nlnk[N+5],dfn[N+5],low[N+5],vis[N+5],Stack[N+5],sum[N+5],In[N+5],vist[N+5];
struct door
{
int x,y,Type,pos,col;
}a[N+5];
struct edge
{
int to,nxt;
}e[2*N+5],ne[2*N+5];
map<point,int> mp;
inline char tc()
{
static char ff[100000],*A=ff,*B=ff;
return A==B&&(B=(A=ff)+fread(ff,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(int &x)
{
x=0;int f=1;char ch;
while(!isdigit(ch=tc())) if(ch=='-') f=-1;
while(x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc()));
x*=f;
}
inline void write(int x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
inline void add(int x,int y)//添加一条新边
{
if(x^y) e[++ee].to=y,e[ee].nxt=lnk[x],lnk[x]=ee;
}
inline void nadd(int x,int y)//添加一条缩点后的新边
{
if(x^y) ne[++nee].to=y,ne[nee].nxt=nlnk[x],nlnk[x]=nee;
}
inline bool cmp_x(door x,door y)//以行为第一关键字进行sort,使每一行都是横天门在最前面
{
if(x.x^y.x) return x.x<y.x;//判断是否在同一行,不是同一行的尽量让行小的在前面
if(x.Type==1&&y.Type^1) return true;//对于同行的,让横天门在最前面
if(x.Type^1&&y.Type==1) return false;
return x.y<y.y;//如果都是或都不是横天门,则列小的在前面
}
inline bool cmp_y(door x,door y)//以列为第一关键字进行sort,使每一列都是纵寰门在最前面
{
if(x.y^y.y) return x.y<y.y;//判断是否在同一列,不是同一列的尽量让列小的在前面
if(x.Type==2&&y.Type^2) return true;//对于同列的,让纵寰门在最前面
if(x.Type^2&&y.Type==2) return false;
return x.x<y.x;//如果都是或都不是纵寰门,则行小的在前面
}
inline bool cmp_z(door x,door y)//对自 由 门的特殊处理,让自 由 门在最前面
{
if(x.Type==3&&y.Type^3) return true;//让自 由 门在最前面
if(x.Type^3&&y.Type==3) return false;
return x.pos<y.pos;//如果都是或都不是自 由 门,则编号小的在前面
}
inline bool cmp_pos(door x,door y)//以编号为第一关键字进行sort,让编号小的在前面,变回读入时的顺序
{
return x.pos<y.pos;
}
inline void Tarjan(int x)//利用Tarjan缩点
{
dfn[x]=low[x]=++d,Stack[++top]=x,vis[x]=1;//记录当前节点的dfs序与当前节点所能到达的dfs序最小的点,将当前节点加入栈中,并标记当前节点在栈中
for(register int i=lnk[x];i;i=e[i].nxt)//枚举从当前节点出发的每一条边
{
if(!dfn[e[i].to]) Tarjan(e[i].to),low[x]=min(low[x],low[e[i].to]);//如果这个节点没访问过,就先对这个节点进行操作,然后更新当前节点能到达的dfs序最小的点
else if(vis[e[i].to]) low[x]=min(low[x],low[e[i].to]);//否则,如果这个点在栈中,就进行更新
}
if(low[x]==dfn[x])//如果当前节点就是当前节点能到达的dfs序最小的点,则对当前强连通分量进行缩点
{
sum[a[x].col=++cnt]=1,vis[x]=0;//给当前节点加入一个新的强连通分量,并将这个新的强连通分量的大小赋值为1,标记当前节点已出栈
while(Stack[top]^x) ++sum[a[Stack[top]].col=cnt],vis[Stack[top--]]=0;//将栈中当前节点之上的节点一一弹出,并更新这个新的强连通分量的大小
--top;//将当前节点弹出
}
}
inline void dfs(int x)//dfs遍历缩点后的图
{
for(register int i=nlnk[x];i;i=ne[i].nxt)//枚举每一条边
{
if(!vist[ne[i].to]) dfs(ne[i].to);//如果这个节点未被访问过,就访问该节点
vist[x]=max(vist[x],vist[ne[i].to]+sum[ne[i].to]);//更新从当前节点出发能得到的最多的宝物数目
}
}
int main()
{
register int i,j;
for(read(n),read(r),read(c),i=1;i<=n;++i)
read(a[i].x),read(a[i].y),read(a[i].Type),a[i].pos=i,mp[make_pair(a[i].x,a[i].y)]=i;
int fst;
sort(a+1,a+n+1,cmp_x);//对接下来对横天门的操作的预处理
for(i=1,fst=0;i<=n;++i)
{
while(i<=n&&a[i].Type^1) ++i;//只要当前门不是横天门,就跳过这个门
if(i>n) continue;
fst=i;//将i标记为该行第一个横天门
while(i<=n&&a[i].x==a[i+1].x&&a[i+1].Type==1) add(a[i].pos,a[i+1].pos),++i;//将前一个横天门与当前横天门连边
add(a[i].pos,a[fst].pos);//将最后一个横天门与第一个横天门连边,形成一个环
while(i<=n&&a[i].x==a[i+1].x) add(a[fst].pos,a[++i].pos);//将该行第一个横天门与该行其他类型的门连边
}
sort(a+1,a+n+1,cmp_y);//对接下来对纵寰门的操作的预处理
for(i=1,fst=0;i<=n;++i)
{
while(i<=n&&a[i].Type^2) ++i;//只要当前门不是纵寰门,就跳过这个门
if(i>n) continue;
fst=i;//将i标记为该列第一个纵寰门
while(i<=n&&a[i].y==a[i+1].y&&a[i+1].Type==2) add(a[i].pos,a[i+1].pos),++i;//将前一个纵寰门与当前纵寰门连边
add(a[i].pos,a[fst].pos);//将最后一个纵寰门与第一个纵寰门连边,形成一个环
while(i<=n&&a[i].y==a[i+1].y) add(a[fst].pos,a[++i].pos);//将该列第一个纵寰门与该列其他类型的门连边
}
sort(a+1,a+n+1,cmp_z);//对接下来对自 由 门的操作的预处理
for(i=1;i<=n&&a[i].Type==3;++i)//枚举每一个自 由 门
{
//枚举每个自 由 门周围的8个宫室,将这个门与周围有宝藏的宫室相连
if(mp[make_pair(a[i].x-1,a[i].y)]) add(a[i].pos,mp[make_pair(a[i].x-1,a[i].y)]);
if(mp[make_pair(a[i].x+1,a[i].y)]) add(a[i].pos,mp[make_pair(a[i].x+1,a[i].y)]);
if(mp[make_pair(a[i].x,a[i].y-1)]) add(a[i].pos,mp[make_pair(a[i].x,a[i].y-1)]);
if(mp[make_pair(a[i].x,a[i].y+1)]) add(a[i].pos,mp[make_pair(a[i].x,a[i].y+1)]);
if(mp[make_pair(a[i].x-1,a[i].y-1)]) add(a[i].pos,mp[make_pair(a[i].x-1,a[i].y-1)]);
if(mp[make_pair(a[i].x+1,a[i].y+1)]) add(a[i].pos,mp[make_pair(a[i].x+1,a[i].y+1)]);
if(mp[make_pair(a[i].x+1,a[i].y-1)]) add(a[i].pos,mp[make_pair(a[i].x+1,a[i].y-1)]);
if(mp[make_pair(a[i].x-1,a[i].y+1)]) add(a[i].pos,mp[make_pair(a[i].x-1,a[i].y+1)]);
}
sort(a+1,a+n+1,cmp_pos);//按照读入时的顺序重新排序
for(i=1;i<=n;++i)
if(!dfn[a[i].pos]) Tarjan(i);//用Tarjan缩点
for(i=1;i<=n;++i)
for(j=lnk[i];j;j=e[j].nxt)
if(a[i].col^a[e[j].to].col) nadd(a[i].col,a[e[j].to].col),++In[a[e[j].to].col];//更新缩点之后点与点之间的边
for(i=1;i<=cnt;++i)
if(!In[i]) dfs(i),ans=max(ans,vist[i]+sum[i]);//贪心的思想,从入度为0的点出发肯定能得到最优答案
return write(ans),0;
}

【洛谷2403】[SDOI2010] 所驼门王的宝藏(Tarjan+dfs遍历)的更多相关文章

  1. 洛谷 2403 [SDOI2010] 所驼门王的宝藏

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

  2. 洛谷 P2403 [SDOI2010]所驼门王的宝藏 题解

    题目描述 分析 先放一张图便于理解 这一道题如果暴力建图会被卡成\(n^{2}\) 实际上,在我们暴力建图的时候,有很多边都是重复的 假如一行当中有许多横天门的话,我们就不必要把这一行当中的所有点和每 ...

  3. 洛咕 P2403 [SDOI2010]所驼门王的宝藏

    简单tarjan. 一行的横天门如果暴力连边会被卡成平方,所以只要相邻两个横天门连双向边,再随便选一个横天门向整行连边即可.纵寰门同理.ziyou门直接map暴力连边. 然后tarjan直接dp. / ...

  4. Luogu 2403 [SDOI2010]所驼门王的宝藏

    BZOJ 1924 内存要算准,我MLE了两次. 建立$n + r + c$个点,对于一个点$i$的坐标为$(x, y)$,连边$(n + x, i)$和$(n + r + y, i)$,代表这一列和 ...

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

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

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. 基于php双引号中访问数组元素

    关于 php访问数组 {} []

  2. Ocelot(五)- 流量限制、服务质量

    Ocelot(五)- 流量限制.服务质量 作者:markjiang7m2 原文地址:https://www.cnblogs.com/markjiang7m2/p/10965300.html 源码地址: ...

  3. (PHP)redis List(列表)操作

    /** * * List操作 * 列表操作 * 可理解为数组操作 * 插入.删除数据按照一定规律排列的 * 元素可重复 * 适用于队列 * */ //在列表头部插入一个值one,当列表不存在时自动创建 ...

  4. 排序工作量之新任务(SHOI2001)

    排序工作量之新任务(SHOI2001) 给出两个整数n和t,求n的全排列中逆序对数为t的个数,和逆序对数为t的字典序最小全排列. 首先第一个问题可以用dp解决,\(f[i][j]\)表示前i个数,j个 ...

  5. 根据T-Code查看用户出口的代码

    在此非常非常感谢源作者,这段代码真的非常非常有用好用! REPORT  YLBTEST. TABLES :  tstc,     "SAP Transaction Codes(SAP 事务代 ...

  6. 洛谷P2846 光开关Light Switching

    题目描述 灯是由高科技--外星人鼠标操控的.你只要左击两个灯所连的鼠标, 这两个灯,以及之间的灯都会由暗变亮,或由亮变暗.右击两个灯所连的鼠 标,你就可以知道这两个灯,以及之间的灯有多少灯是亮的.起初 ...

  7. 如何理解javascript中的同步和异步

    javascript语言是一门“单线程”的语言,不像java语言,类继承Thread再来个thread.start就可以开辟一个线程,所以,javascript就像一条流水线,仅仅是一条流水线而已,要 ...

  8. Vue 3 --安装脚手架、过滤器、生命周期的钩子函数、vue-router基本使用

    一.安装脚手架 1.下载node.js,本文下载版本为node-v8.12.0-x64.msi,一键式安装. 2.安装完成后,打开终端,输入node,可进入node环境(两次ctrl+c退出),如下图 ...

  9. js 提示样式 ? 上写提示内容

    //再需要的地方放入 <img dms_map_key="zs_prise" src="${ctx }/static/image/tip.png" cla ...

  10. Storm概念学习系列之事务

    不多说,直接上干货! 事务 这里的事务是专门针对Topology提出来的,是为了解决元组在处理失败重新发送后的一系列问题的.简而言之,事务拓扑(transactional topology)就是指St ...