二进制分组也可以说是一种比较优美的拆贡献方式吧?

Description

菩萨为行,福慧双修,智人得果,不忘其本。
——唐朠立《大慈恩寺三藏法师传》
有才而知进退,福慧双修,这才难得。
——乌雅氏
如何福慧双修?被太后教导的甄嬛徘徊在御花园当中。突然,她发现御花园中的花朵全都是红色和蓝色的。她冥冥之中得到了响应:这就是指导她如何福慧双修的! 现在御花园可以看作是有N块区域,M条小路,两块区域之间可通过小路连接起来。现在甄嬛站在1号区域,而她需要在御花园中绕一绕,且至少经过1个非1号区 域的区域。但是恰好1号区域离碎玉轩最近,因此她最后还是要回到1号区域。由于太后教导她要福慧双修,因此,甄嬛不能走过任何一条她曾经走过的路。但是, 御花园中来往的奴才们太多了,而且奴才们前行的方向也不一样,因此甄嬛在走某条小路的时候,方向不同所花的时间不一定一样。天色快暗了,甄嬛需要尽快知道 至少需要花多少时间才能学会如何福慧双修。如果甄嬛无法达到目的,输出“-1”。

Input

第一行仅2个正整数n,m,意义如题。
接下来m行每行4个正整数s,t,v,w,其中s,t为小路所连接的两个区域的编号,v为甄嬛从s到t所需的时间,w为甄嬛从t到s所需的时间。数据保证无重边。

Output

仅一行,为甄嬛回到1号区域所需的最短时间,若方案不存在,则输出-1

HINT

[样例解释]

对于第一个数据:路径为1->2->3->1,所需时间为8,而1->3->2->1所花时间为9。因此答案为8.

[数据范围与约定]

对于40%的数据:n<=1,000; m<=5,000

对于100%的数据:1<=n<=40,000; 1<=m<=100,000; 1<=v,w<=1,000


题目分析

首先考虑一些性质。对于不与1相连的边,由于边权为正,所以它们是一定不会经过多次的,那么这个限制相当于就去掉了。接下去的问题就出在与1相连的边这里,因为可能从同一条边出入1点最优。

朴素做法:指定一条出边和一条入边,每次计算答案。

考虑答案的出入边$i$和$j$,那么$i,j$一定有一个二进制位不同。于是我们枚举不同的二进制位,将该位为0/1的两类边分别分成出边/入边集合,做完一次dij就枚举入边统计答案。

时间复杂度:$O(n\log^2n)$.

后话:这个做法复杂度在这两题确实有点大了。两题差不多都拿了倒数前20吧。

 1 #include<bits/stdc++.h>
 2 const int maxn = 40035;
 3 const int maxm = 200035;
 4
 5 struct Edge
 6 {
 7     int v,c;
 8     Edge(int a=0, int b=0):v(a),c(b) {}
 9 }edges[maxm];
10 struct node
11 {
12     int x,d;
13     node(int a=0, int b=0):x(a),d(b) {}
14     bool operator < (node a) const
15     {
16         return d > a.d;
17     }
18 };
19 int n,m,ans,dis[maxn],dfn[maxn],tim;
20 int edgeTot,head[maxn],nxt[maxm],tag[maxm];
21 std::priority_queue<node> q;
22
23 int read()
24 {
25     char ch = getchar();
26     int num = 0, fl = 1;
27     for (; !isdigit(ch); ch=getchar())
28         if (ch=='-') fl = -1;
29     for (; isdigit(ch); ch=getchar())
30         num = (num<<1)+(num<<3)+ch-48;
31     return num*fl;
32 }
33 void addedge(int u, int v, int c)
34 {36     edges[++edgeTot] = Edge(v, c), nxt[edgeTot] = head[u], head[u] = edgeTot;
37 }
38 void dijkstra()
39 {
40     memset(dis, 0x3f3f3f3f, sizeof dis);
41     ++tim, q.push(node(1, 0)), dis[1] = 0;
42     for (node tmp; q.size(); )
43     {
44         tmp = q.top(), q.pop();
45         if (dfn[tmp.x]==tim) continue;
46         dfn[tmp.x] = tim;
47         for (int i=head[tmp.x]; i!=-1; i=nxt[i])
48             if (tag[i]!=-1)
49             {
50                 int v = edges[i].v;
51                 if (dis[v] > dis[tmp.x]+edges[i].c)
52                     dis[v] = dis[tmp.x]+edges[i].c, q.push(node(v, dis[v]));
53             }
54     }
56     for (int i=head[1]; i!=-1; i=nxt[i])
57         if (tag[i]==-1&&(ans==-1||(ans > dis[edges[i].v]+edges[i^1].c)))
58             ans = dis[edges[i].v]+edges[i^1].c;
59 }
60 int main()
61 {
62     memset(head, -1, sizeof head);
63     n = read(), m = read(), ans = edgeTot = -1;
64     for (int i=1; i<=m; i++)
65     {
66         int u = read(), v = read(), s = read(), t = read();
67         addedge(u, v, s), addedge(v, u, t);
68     }
69     for (int d=18; d>=0; --d)
70     {
71         for (int i=head[1]; i!=-1; i=nxt[i])
72             if ((i>>d)&1) tag[i] = 0, tag[i^1] = -1;
73             else tag[i] = -1, tag[i^1] = 0;
74         dijkstra();
75         for (int i=head[1]; i!=-1; i=nxt[i])
76             if ((i>>d)&1) tag[i] = -1, tag[i^1] = 0;
77             else tag[i] = 0, tag[i^1] = -1;
78         dijkstra();
79     }
80     printf("%d\n",ans);
81     return 0;
82 }

END

转载于:https://www.cnblogs.com/antiquality/p/11201322.html

【技巧 二进制分组】bzoj4398: 福慧双修2407: 探险相关推荐

  1. [BZOJ4398]福慧双修/[BZOJ2407]探险

    题目大意: 给定一个$n(n\leq40000)$个点$m(m\leq100000)$条边的有向图,求从$1$出发回到$1$的不经过重复结点的最短路. 思路: 首先Dijkstra求出从1出发到每个结 ...

  2. BZOJ 2407: 探险/BZOJ 4398: 福慧双修 dijkstra 构造

    2407: 探险 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 170  Solved: 95 [Submit][Status][Discuss] ...

  3. bzoj 4398 福慧双修——二进制分组

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4398 如果枚举1号点走哪些点出去,就从那些点出发跑多源最短路即可.最短路不会重复经过一条边. ...

  4. BZOJ 2407: 探险/4398: 福慧双修

    2407: 探险 Description 探险家小T好高兴!X国要举办一次溶洞探险比赛,获奖者将得到丰厚奖品哦!小T虽然对奖品不感兴趣,但是这个大振名声的机会当然不能错过! 比赛即将开始,工作人员说明 ...

  5. [bzoj4398]福慧双修

    [bzoj4398]福慧双修 要求不能走重复的边,路径就是1->u->v->1,然后我们可以i想到一个暴力:把1去掉 枚举u跑最短路然后枚举v更新答案.因为边权非负,这个肯定是合法的 ...

  6. bzoj29894170数列——二进制分组+主席树

    题意的转化挺巧妙的 可以联想到曼哈顿距离! 并且,所谓的修改还要查询历史版本,并且修改之间不动只算一次,不就是给平面上加一个点吗? 看成(x,a[x])的点 就是一个菱形区域 转切比雪夫距离,变成矩形 ...

  7. 【BZOJ3821/UOJ46】玄学(二进制分组,线段树)

    [BZOJ3821/UOJ46]玄学(二进制分组,线段树) 题面 BZOJ UOJ 题解 呜,很好的题目啊QwQ. 离线做法大概可以线段树分治,或者直接点记录左右两次操作时的结果,两个除一下就可以直接 ...

  8. 【BZOJ2069】ZAW(POI2004)-最短路+二进制分组

    测试地址:ZAW 题目大意: 给定一张边是双向的图,一条边走不同的方向可能代价不同,代价都非负,求从点111出发,不经过重复的点或边的最小回路.n≤5000,m≤10000n\le 5000,m\le ...

  9. BZOJ_4398_福慧双修BZOJ_2407_探险_分治+dij

    BZOJ_4398_福慧双修&&BZOJ_2407_探险_分治+dij Description 菩萨为行,福慧双修,智人得果,不忘其本. --唐朠立<大慈恩寺三藏法师传> ...

最新文章

  1. (附下载地址)制作RPM包(星际译王词典包)
  2. SparkStreaming读取Kakfa数据时发生OffsetOutOfRangeException异常
  3. Authentication 方案优化探索(JWT, Session, Refresh Token, etc.)
  4. 小白学phoneGap《构建跨平台APP:phoneGap移动应用实战》连载四(使用程序载入事件)...
  5. 回溯法解决四皇后问题
  6. VS2017调试时如何查看内存
  7. hexo-cli博客 hexo-admin编辑器 next主题安装命令整理
  8. 关系数据库设计理论(函数依赖、异常、范式)、ER图
  9. web mysql 报表_由简到难生成数据库报表(一)
  10. MapReduce基础
  11. python嵌套列表索引 index_Python:嵌套lis中元素的索引列表
  12. java中线程的状态以及线程栈分析
  13. 【sketchup 2021】草图大师图像输出与渲染之Enscape渲染(优秀的实时渲染软件)的基本使用【渲染实时更新与同步、在线资源库、渲染和常规设置(图标背景、草地渲染)、导出为图像和独立文件】
  14. 物联网之卫星导航系统
  15. “铜三铁四“来一套程序员内卷超车赛道-音视频开发
  16. python实现将图像合成GIF图
  17. Python 爬虫 Vimeo视频下载链接
  18. 深入理解蓝牙5之高数据传输率
  19. 滴滴滴,安装Elastic找我就够了
  20. 【英文知识】小学英语同音字、近义词整理

热门文章

  1. C语言新手记:数列分段
  2. 我自己很喜欢的几款文案编辑软件
  3. 刷机案例-----谷歌pixel系列机型刷写系统的一些问题解析
  4. R语言和医学统计学(3):卡方检验
  5. 关于定制开发ERP的哪些事,5分钟看懂ERP定制开发关键节点
  6. vue解决-4048报错
  7. 计算机一级基本操作题创建快捷方式,计算机一级MSOffice操作题练习附答案
  8. java ibatis mybatis_Mybatis与Ibatis的区别
  9. STC89C52RC - 11 - 蜂鸣器BEEP
  10. xx第一天蓝队 信息安全_信息保护,第1部分,信息安全