题意

有n个点,m条双向道路,其中第条公路的两个端点是u[i],v[i],费用是c[i]。

现在给出q个询问,每次给定一个L和一个R,要求你只能够使用[L,R]这个区间内的边,是的连接之后,连通块的数量最小。在保证连通块数量最小的情况下,求最少需要的代价(可以拿一些边不用)。

输入格式

第一行三个整数n,m,q,含义如图所示

接下来m行,每行3个整数,描述一条边,分别是u,v,c。

接下来q行,每行2个整数L,R,表示一次询问。

输出格式

对于每一个询问,输出一个整数表示最小连通块意义下的最小代价。

数据范围

n<=100,m<100000,q<=15000

思路

这道题还正是神奇...

看完题目之后,不难得出题目的要求就是让我们用[L,R]之间的边求一个最小生成树。然后我们就有了一个\(O(m*q*\log m )\)的暴力算法。

然而在考场上,自己脑残了...想了几分钟之后,这不是...回滚莫队吗?正好可以去掉难搞的删除操作,然后...再用LCT来回答LCA...好像不可做欸...然后全程想怎么优化...然后就...GG。

看完题解之后,发现好像以前见过类似的做法,但是...似乎有没有...

题解的大致思路就是:

对于m条边建一个线段树,下标就是边的标号,然后对于一个线段树区间[L,R],这个节点上存的是使用[L,R]这个区间的边,求得的最小生成树使用了的边的编号(用数组存在线段树结点里)。因为最多会使用n-1条边,那么就最多会存\(O(m * 4 *n)\)个数字,是不会炸的。

然后怎么合并呢?因为我们一个节点里最多只会塞n-1条边(体现为编号),那么我们就可以直接暴力合并!也就是用Kruskal暴力合并即可。但需要注意的是,不能直接把当前线段树节点的左右儿子的边集直接存下来然后排序跑Kruskal,而应该利用归并排序的思想,直接用双指针在左右两个儿子的边集中扫一下就可以了。

然后处理询问的时候就利用线段树的结构,将询问的区间拆成\(\log m\)个子区间,然后暴力合并即可。

最后总的时间复杂度就是\(O((m\log m+q\log m)n*f(n))\),其中f(n)代表的是n个点的路径压缩版本的并查集的复杂度。

去你的回滚莫队

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#define MAXN 100
#define MAXM 100000
#define MAXQ 15000
using namespace std;
struct edge
{
int u,v,w;
edge(){};
edge(int _u,int _v,int _w):u(_u),v(_v),w(_w){};
}edges[MAXM+5];
bool operator < (const edge &a,const edge &b)
{return a.w<b.w;}
bool cmp(const int &a,const int &b)
{return edges[a]<edges[b];}
struct TreeNode
{
int seq[MAXN*2+5];//第0位存长度
}tree[MAXM*4];
int n,m,q,setfa[MAXN+5];
int ANS[MAXN*2+5],ANSval;//答案用的边集ANS[],以及最小代价ANSval
int Findfa(int x)
{
if(setfa[x]==x)
return x;
return setfa[x]=Findfa(setfa[x]);
}
bool Union(int x,int y)
{
x=Findfa(x),y=Findfa(y);
if(x==y)
return false;
setfa[x]=y;
return true;
}
void Init()
{
for(int i=1;i<=n;i++)
setfa[i]=i;
}
void Merge(int *seq,int *seq1,int *seq2)//把seq1和seq2合并到seq中
{
static int tmp[MAXN*2+5];//归并排序进行Kruskal,以规避sort的log(卡常数)
tmp[0]=0;Init();
int i=1,j=1;
while(i<=seq1[0]||j<=seq2[0])
{
if(j>seq2[0]||(i<=seq1[0]&&edges[seq1[i]].w<edges[seq2[j]].w))
{
if(Union(edges[seq1[i]].u,edges[seq1[i]].v))
tmp[++tmp[0]]=seq1[i];
i++;
}
else
{
if(Union(edges[seq2[j]].u,edges[seq2[j]].v))
tmp[++tmp[0]]=seq2[j];
j++;
}
}
for(int i=0;i<=tmp[0];i++)
seq[i]=tmp[i];
}
void Build(int i,int l,int r)
{
if(l==r)
{
tree[i].seq[0]=1;
tree[i].seq[1]=l;
return;
}
int mid=(l+r)/2;
Build(i*2,l,mid);
Build(i*2+1,mid+1,r);
Merge(tree[i].seq,tree[i*2].seq,tree[i*2+1].seq);
}
void Query(int i,int l,int r,int ql,int qr)
{
if(qr<l||ql>r)
return;
if(ql<=l&&r<=qr)
{
Merge(ANS,ANS,tree[i].seq);
return;
}
int mid=(l+r)/2;
Query(i*2,l,mid,ql,qr);
Query(i*2+1,mid+1,r,ql,qr);
}
inline int read()
{
int ret=0;char c=0;
while(c<'0'||c>'9') c=getchar();
ret=10*ret+c-'0';
while(true){c=getchar();if(c<'0'||c>'9') break;ret=10*ret+c-'0';}
return ret;
}
inline void print(int x)
{
if(x==0) return;
print(x/10);
putchar(x%10+'0');
}
int main()
{
// freopen("highway.in","r",stdin);
// freopen("highway.out","w",stdout);
scanf("%d %d %d",&n,&m,&q);
int u,v,c;
for(int i=1;i<=m;i++)
{
u=read(),v=read(),c=read();
edges[i]=edge(u,v,c);
}
Build(1,1,m);
for(int i=1;i<=q;i++)
{
int l,r;
l=read(),r=read();
ANS[0]=0,ANSval=0;
Query(1,1,m,l,r);
for(int i=1;i<=ANS[0];i++)
ANSval+=edges[ANS[i]].w;//最后统一算答案
print(ANSval);putchar('\n');
}
return 0;
}
/*
3 5 2
1 3 2
2 3 1
2 1 6
3 1 7
2 3 7
2 5
3 4 */

【省选十连测之一】【线段树】【最小生成树之Kruskal】公路建设的更多相关文章

  1. 4.11 省选模拟赛 序列 二分 线段树优化dp set优化dp 缩点

    容易想到二分. 看到第一个条件容易想到缩点. 第二个条件自然是分段 然后让总和最小 容易想到dp. 缩点为先:我是采用了取了一个前缀最小值数组 二分+并查集缩点 当然也是可以直接采用 其他的奇奇怪怪的 ...

  2. 3.28 省选模拟赛 染色 LCT+线段树

    发现和SDOI2017树点涂色差不多 但是当时这道题模拟赛的时候不会写 赛后也没及时订正 所以这场模拟赛的这道题虽然秒想到了LCT和线段树但是最终还是只是打了暴力. 痛定思痛 还是要把这道题给补了. ...

  3. 【CSA72G】【XSY3316】rectangle 线段树 最小生成树

    题目大意 有一个 \(n\times n\) 的矩阵 \(A\).最开始 \(A\) 中每个元素的值都为 \(0\). 有 \(m\) 次操作,每次给你 \(x_1,x_2,y_1,y_2,w\),对 ...

  4. 【JZOJ5060】【GDOI2017第二轮模拟day1】公路建设 线段树+最小生成树

    题面 在Byteland一共有n 个城市,编号依次为1 到n,它们之间计划修建m条双向道路,其中修建第i 条道路的费用为ci. Byteasar作为Byteland 公路建设项目的总工程师,他决定选定 ...

  5. [bzoj省选十连测推广赛2]T2七彩树

    抄自:http://blog.csdn.net/coldef/article/details/61412577 当时看了就不会,看了别人的题解不懂怎么维护,最后抄了个代码....... 给定一棵n个点 ...

  6. bzoj省选十连测推广赛

    A.普通计算姬 题意:给丁一棵树,每个点有一个权值,用sum(x)表示以x为根的子树的权值和,要求支持两种操作: 1 u v  :修改点u的权值为v. 2 l  r   :  求∑sum[i] l&l ...

  7. 【省选十连测之九】【DP】【组合计数去重】【欧拉函数】基本题

    目录 题意: 输入格式: 输出格式: 数据范围: 思路: 嵌套题的转移 基本题的转移 Part1 Part2 Part3 代码 题意: 这是一个关于括号组合的题. 首先定义一道题是由'(',')',' ...

  8. 【正睿oi省选十连测】第一场

    四小时写了两个暴力??自闭 [原来这就是神仙们的分量Orz rank 56/75 可以说是无比垃圾了 下周目标:进步十名?[大雾 T1 题意:有n个点的图 点有点权Ai 也有点权Bi = A_1 + ...

  9. 洛谷P4065 [JXOI2017]颜色(线段树)

    题意 题目链接 Sol 线段树板子题都做不出来,真是越来越菜了.. 根据题目描述,一个合法区间等价于在区间内的颜色没有在区间外出现过. 所以我们可以对于每个右端点,统计最长的左端点在哪里,刚开始以为这 ...

随机推荐

  1. js 时间格式化 兼容safari 苹果手机

    export function formatTime (fmt, date) { date = new Date(date + '+08:00') // 兼容safari var o = { 'M+' ...

  2. IPv6 RIPng (PT)

    在Cisco路由器上配置RIPng  一.拓扑图 二.地址表 Device Interface IPv6 Address R1 F 0/0 2001:0DB8:CAFE:0001::1/64 S 0/ ...

  3. Ajax简述

    AJAX即“Asynchronous Javascript And XML”(异步JavaScript和XML),是指一种创建交互式网页应用的网页开发技术.AJAX = 异步 JavaScript和X ...

  4. Aras简单报表

    1.编辑Report对象类的窗体Report_Tab_Report,将xsl_stylesheet放到窗体上 2.新建报表 3.将编辑好的XSLT复制到xsl_stylesheet中. <xsl ...

  5. Dynamic Rankings

    板子题 用的整体二分 唯一要注意的是别总手误打错变量 最近总犯这样sb错误,我佛了 #include<bits/stdc++.h> using namespace std; const i ...

  6. Selenium中三种等待的使用方式---规避网络延迟、代码不稳定问题

    在UI自动化测试中,必然会遇到环境不稳定,网络慢的情况,这时如果你不做任何处理的话,代码会由于没有找到元素,而报错.这时我们就要用到wait(等待),而在Selenium中,我们可以用到一共三种等待, ...

  7. 《模式分类(原书第二版)》pdf格式下载电子书免费下载

    <模式分类(原书第二版)>pdf格式下载电子书免费下载: https://u253469.ctfile.com/fs/253469-302448505 内容简介 <模式分类>( ...

  8. MailKit系列之附件分离

    本文主要谈谈实现思路,不提供完整代码 一.分离基础 1.MIME邮件的multipart类型 引用文章:https://blog.csdn.net/wangyu13476969128/article/ ...

  9. 【medium】4. Median of Two Sorted Arrays 两个有序数组中第k小的数

    There are two sorted arrays nums1 and nums2 of size m and n respectively. Find the median of the two ...

  10. 统计信息不准导致sql性能下降

    某局的预生产系统一条sql语句20分钟执行完,上线以后2个小时没执行出来,在预生产执行计划是hash join在生产是nested loop,通过awr基表wri$_optstat_tab_histo ...