题目链接

https://www.lydsy.com/JudgeOnline/problem.php?id=4388

题解

模拟Prim算法?

原题所述的过程就是Prim算法求最大生成树的过程。于是我们可以知道起始点并没有影响。

那么就用数据结构模拟Prim算法吧。

首先离散化所有区间,每个区间只需要一个点和外面相连,其余点均按照覆盖该点区间的最大权值与这个点相连。因此简单利用线段树即可求出这一部分的答案。

对于剩下的部分,用维护\(T\)表示目前没有加入的点,先加入左边\(1\)号点,同时用大根堆维护已加入点和未加入点之间的连边(也就是有一部分已加入一部分未加入的区间)

每次从堆中取出一个区间,随便找一个该区间内还在\(T\)集中的点(若不存在就什么都不干),把它从\(T\)集中删掉,顺便把包含它的所有没访问过的区间加入队列

这个可以使用线段树实现,两棵线段树分别维护两边的点,把每个区间拆成\(\log\)段,放到线段树的每个节点上,顺便维护每个区间内依然存在的点的最大值(或最小值,目的就是随便找一个点),每次删掉一个点的时候删掉线段树从根到它的所有区间并扔进堆里,并且把这个点标记为不存在(最大值改成\(0\)).

这一部分使用vector实现可能会MLE,可以使用链表实现。

总时间复杂度\(O(n\log n)\).

代码

#include<bits/stdc++.h>
#define llong long long
#define pii pair<int,int>
#define mkpr make_pair
using namespace std; const int N = 2e5;
const int SIZ = 3.5e6; struct Element
{
int lx,ly,rx,ry; llong w;
bool operator <(const Element &arg) const {return w>arg.w;}
} qr[N+3];
priority_queue<pii> pq;
bool del[N+3]; struct SegmentTree
{
struct List
{
int nxt,val;
} li[SIZ+3];
struct SgTNode
{
int fe;
int maxi;
} sgt[(N<<2)+3];
int siz;
void build(int u,int le,int ri)
{
sgt[u].maxi = ri;
if(le==ri) {return;}
int mid = (le+ri)>>1;
build(u<<1,le,mid); build(u<<1|1,mid+1,ri);
}
void insert(int u,int le,int ri,int lb,int rb,int x)
{
if(lb>rb) {return;}
if(le>=lb && ri<=rb) {siz++; li[siz].nxt = sgt[u].fe; li[siz].val = x; sgt[u].fe = siz; return;}
int mid = (le+ri)>>1;
if(lb<=mid) {insert(u<<1,le,mid,lb,rb,x);}
if(rb>mid) {insert(u<<1|1,mid+1,ri,lb,rb,x);}
}
int query(int u,int le,int ri,int lb,int rb)
{
if(lb>rb) {return 0;}
if(le>=lb && ri<=rb) {return sgt[u].maxi;}
int mid = (le+ri)>>1,ret = 0;
if(lb<=mid) {ret = max(ret,query(u<<1,le,mid,lb,rb));}
if(rb>mid) {ret = max(ret,query(u<<1|1,mid+1,ri,lb,rb));}
return ret;
}
void delet(int u,int le,int ri,int pos)
{
for(int &i=sgt[u].fe; i; i=li[i].nxt)
{
if(!del[li[i].val]) {del[li[i].val] = true; pq.push(mkpr(qr[li[i].val].w,li[i].val));}
}
if(le==ri) {sgt[u].maxi = 0; return;}
int mid = (le+ri)>>1;
if(pos<=mid) {delet(u<<1,le,mid,pos);}
else {delet(u<<1|1,mid+1,ri,pos);}
sgt[u].maxi = max(sgt[u<<1].maxi,sgt[u<<1|1].maxi);
}
} sgt1,sgt2; struct SegmentTree2
{
int maxi[(N<<2)+3];
void insert(int u,int le,int ri,int lb,int rb,int x)
{
if(lb>rb) return;
if(le>=lb && ri<=rb) {maxi[u] = max(maxi[u],x); return;}
int mid = (le+ri)>>1;
if(lb<=mid) {insert(u<<1,le,mid,lb,rb,x);}
if(rb>mid) {insert(u<<1|1,mid+1,ri,lb,rb,x);}
}
int query(int u,int le,int ri,int pos)
{
if(le==ri) {return maxi[u];}
int mid = (le+ri)>>1;
if(pos<=mid) {return max(maxi[u],query(u<<1,le,mid,pos));}
else {return max(maxi[u],query(u<<1|1,mid+1,ri,pos));}
}
} sgt3,sgt4; vector<int> discx,discy;
int n,m,q;
llong ans; int getdiscx(int x) {return lower_bound(discx.begin(),discx.end(),x)-discx.begin();}
int getdiscy(int x) {return lower_bound(discy.begin(),discy.end(),x)-discy.begin();} int main()
{
scanf("%d%d%*d%d",&n,&m,&q);
for(int i=1; i<=q; i++)
{
scanf("%d%d%d%d%lld",&qr[i].lx,&qr[i].rx,&qr[i].ly,&qr[i].ry,&qr[i].w);
discx.push_back(qr[i].lx-1),discx.push_back(qr[i].rx),discy.push_back(qr[i].ly-1),discy.push_back(qr[i].ry);
}
discx.push_back(0),discy.push_back(0);
sort(discx.begin(),discx.end()); discx.erase(unique(discx.begin(),discx.end()),discx.end());
sort(discy.begin(),discy.end()); discy.erase(unique(discy.begin(),discy.end()),discy.end());
for(int i=1; i<=q; i++)
{
qr[i].lx = getdiscx(qr[i].lx-1)+1,qr[i].rx = getdiscx(qr[i].rx),qr[i].ly = getdiscy(qr[i].ly-1)+1,qr[i].ry = getdiscy(qr[i].ry);
}
n = discx.size()-1,m = discy.size()-1;
sgt1.build(1,1,n); sgt2.build(1,1,m);
for(int i=1; i<=q; i++)
{
sgt3.insert(1,1,n,qr[i].lx,qr[i].rx,qr[i].w);
sgt4.insert(1,1,m,qr[i].ly,qr[i].ry,qr[i].w);
sgt1.insert(1,1,n,qr[i].lx,qr[i].rx,i);
sgt2.insert(1,1,m,qr[i].ly,qr[i].ry,i);
}
for(int i=1; i<=n; i++)
{
ans += 1ll*sgt3.query(1,1,n,i)*(discx[i]-discx[i-1]-1ll);
}
for(int i=1; i<=m; i++)
{
ans += 1ll*sgt4.query(1,1,m,i)*(discy[i]-discy[i-1]-1ll);
}
sgt1.delet(1,1,n,1);
while(!pq.empty())
{
int i = pq.top().second; pq.pop();
int ux = sgt1.query(1,1,n,qr[i].lx,qr[i].rx);
if(ux)
{
ans += qr[i].w;
sgt1.delet(1,1,n,ux);
pq.push(mkpr(qr[i].w,i));
continue;
}
int uy = sgt2.query(1,1,m,qr[i].ly,qr[i].ry);
if(uy)
{
ans += qr[i].w;
sgt2.delet(1,1,m,uy);
pq.push(mkpr(qr[i].w,i));
}
}
if(sgt1.sgt[1].maxi||sgt2.sgt[1].maxi) {puts("-1"); return 0;}
printf("%lld\n",ans);
return 0;
}

BZOJ 4388 [JOI2012春季合宿]Invitation (线段树、二叉堆、最小生成树)的更多相关文章

  1. BZOJ 4221 [JOI2012春季合宿]Kangaroo (DP)

    题目链接 https://www.lydsy.com/JudgeOnline/problem.php?id=4221 题解 orz WYC 爆切神仙DP 首先将所有袋鼠按大小排序.考虑从前往后DP, ...

  2. [JOI2012春季合宿]Rotate (链表)

    题意 题解 又是一道神仙题-- 显然的做法是大力splay,时间复杂度\(O((N+Q)N\log N)\), 可以卡掉. 正解: 使用十字链表维护矩阵,在周围增加第\(0\)行/列和第\((n+1) ...

  3. [JOI2012春季合宿]Constellation (凸包)

    题意 题解 神仙结论题. 结论: 一个点集合法当且仅当其凸包上的两种颜色点分别连续. 证明: 必要性显然. 充分性: 考虑对于一个不同色三角形\(ABC\),不妨设点\(A\)为白点,点\(B,C\) ...

  4. [BZOJ 3123] [SDOI 2013]森林(可持久化线段树+并查集+启发式合并)

    [BZOJ 3123] [SDOI 2013]森林(可持久化线段树+启发式合并) 题面 给出一个n个节点m条边的森林,每个节点都有一个权值.有两种操作: Q x y k查询点x到点y路径上所有的权值中 ...

  5. 【bzoj5210】最大连通子块和 树链剖分+线段树+可删除堆维护树形动态dp

    题目描述 给出一棵n个点.以1为根的有根树,点有点权.要求支持如下两种操作: M x y:将点x的点权改为y: Q x:求以x为根的子树的最大连通子块和. 其中,一棵子树的最大连通子块和指的是:该子树 ...

  6. 【BZOJ 1129】[POI2008]Per 二叉堆

    这个东西读完题之后,就能知道我们要逐位计算贡献.推一下式子,会发现,这一位的贡献,是当前剩余的数字形成的序列的总数,乘上所剩数字中小于s上这一位的数的个数与所剩数字的总数的比.所以我们维护“当前剩余的 ...

  7. BZOJ.5110.[CodePlus2017]Yazid 的新生舞会(线段树/树状数组/分治)

    LOJ BZOJ 洛谷 又来发良心题解啦 \(Description\) 给定一个序列\(A_i\).求有多少个子区间,满足该区间众数出现次数大于区间长度的一半. \(n\leq5\times10^5 ...

  8. BZOJ.2653.[国家集训队]middle(可持久化线段树 二分)

    BZOJ 洛谷 求中位数除了\(sort\)还有什么方法?二分一个数\(x\),把\(<x\)的数全设成\(-1\),\(\geq x\)的数设成\(1\),判断序列和是否非负. 对于询问\(( ...

  9. 有趣的线段树模板合集(线段树,最短/长路,单调栈,线段树合并,线段树分裂,树上差分,Tarjan-LCA,势能线段树,李超线段树)

    线段树分裂 以某个键值为中点将线段树分裂成左右两部分,应该类似Treap的分裂吧(我菜不会Treap).一般应用于区间排序. 方法很简单,就是把分裂之后的两棵树的重复的\(\log\)个节点新建出来, ...

随机推荐

  1. GCN代码分析 2019.03.12 22:34:54字数 560阅读 5714 本文主要对GCN源码进行分析。

    GCN代码分析   1 代码结构 . ├── data // 图数据 ├── inits // 初始化的一些公用函数 ├── layers // GCN层的定义 ├── metrics // 评测指标 ...

  2. O061、Boot from Volume

    参考https://www.cnblogs.com/CloudMan6/p/5679384.html   Volume 除了可以用作Instance的数据盘,也可以作为启动盘(Bootable Vol ...

  3. JavaScript使用纯函数避免bug

    纯函数 一.纯函数 定义:纯函数是指不依赖并且不修改其作用域之外的函数.通过以下几个示例来认识纯函数: var a = 10; //纯函数 function foo(num){ return num ...

  4. javascrip标签的href属性

    1.标签的href属性用于指定超链接目标的URL.href属性的值可以是任何有效文档的相对或绝对URL,包括片段ID和javascript代码段. 2.javascript:这是一个虚假的协议.所谓的 ...

  5. C# 斐波那契数列 第n项数字/前n项的和

    static void Main(string[] args) { int a = Convert.ToInt32(Console.ReadLine()); //求第n位数字是多少 Console.W ...

  6. BootStrape基础使用

    官网:www.bootcss.com 一. 全局css样式 栅格系统 栅格系统用于通过一系列的行(row)与列(column)的组合来创建页面布局 <!DOCTYPE html> < ...

  7. IIS 6.0 PUT上传 任意文件创建漏洞

    IIS 6.0 PUT上传 任意文件创建漏洞 require 1.IIS Server在Web服务扩展中开启了WebDAV. 2.IIS配置了可以写入的权限,包括网站 1.根目录 2.子文件夹 3.i ...

  8. vbox的四种网络模式

      一.NAT模式 特点: 1.如果主机可以上网,虚拟机可以上网 2.虚拟机之间不能ping通 3.虚拟机可以ping通主机(此时ping虚拟机的网关,即是ping主机) 4.主机不能ping通虚拟机 ...

  9. ADO.net 数据库连接new SqlConnection、Open、Close、Dispose

    今天踩了一个坑,用了一个static对象,存储了Connection,导致了并发量大时(35/s)出现单个连接的数据库请求堆积,以及并发Open导致的异常,最终使服务下线. 排查中发现有些概念不清的地 ...

  10. Hadoop_11_HDFS的流式 API 操作

    对于MapReduce等框架来说,需要有一套更底层的API来获取某个指定文件中的一部分数据,而不是一整个文件 因此使用流的方式来操作 HDFS上的文件,可以实现读取指定偏移量范围的数据 1.客户端测试 ...