Codeforces.1051G.Distinctification(线段树合并 并查集)
\(Description\)
给定\(n\)个数对\(A_i,B_i\)。你可以进行任意次以下两种操作:
- 选择一个位置\(i\),令\(A_i=A_i+1\),花费\(B_i\)。必须存在一个位置\(j\),满足\(A_i=A_j,\ i\neq j\),才可以进行。
- 选择一个位置\(i\),令\(A_i=A_i-1\),花费\(-B_i\)。必须存在一个位置\(j\),满足\(A_i=A_j+1\),才可以进行。
你需要对于所有\(i\in[1,n]\),求使得\(A_1,A_2,...,A_i\)两两不同的最小花费是多少。
\(n,A_i\leq2\times10^5,\ 1\leq B_i\leq n且互不相同\)。
\(Solution\)
考虑如果\(A_i\)互不相同,若存在\(A_i+1=A_j\),则可以交换\(A_i,A_j\),花费为\(B_i-B_j\)。所以最后序列会被分成\(A_i\)连续的若干段,且每段\(B_i\)递减。
如果\(A_i\)有可能相同,可以先把\(A_i\)变成互不相同(把相同的位置上的数移到该连续段的右端点\(+1\)处,并查集维护),再进行同样的操作。
设数\(A_i\)最终变成了\(A_i'\)(按\(B_i\)排序后被放到了\(A_i'\)位置去),我们发现\(i\)的贡献就是\((A_i'-A_i)\times B_i\),也就是所有数的贡献是\(\sum_i A_i'\times B_i-\sum_i A_i\times B_i\)。所以我们只需要在按\(B_i\)排序的过程中维护每个元素新的位置及贡献(其实维护位置就是维护在连续段中的排名,直接插入即可)。
具体就是,对于一个连续段,以\(B_i\)为下标建线段树。最后\(B_i\)是递减的,所以每个区间的贡献就是,\(左区间的\sum B_i\times 右区间的元素个数\)(当然这只是段内相对排名改变的贡献,连续段整体还有 \(连续段左端点\times\sum B_i\)的贡献)。
加入一个\(A_i\)时,可能把两个连续段合并在一起。把原先两个连续段的贡献减掉,然后线段树合并两段,再加上合并后的段的贡献即可。
复杂度\(O(n\log n)\)(为啥\(Tutorial\)上写的是\(O(n\log^2n)\)...?没细看...)。
注意数组大小要开\(4e5\)!不是\(2e5\)!(值域会扩大)
当你连WA 8遍且发现输出都不一样的时候,基本就是RE了= = 气死我了
ps:似乎不用维护左端点,有右端点有\(size\)不就有左端点了吗。
//483ms 161100KB
#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
typedef long long LL;
const int N=4e5+3;//4e5 not 2e5!
int fa[N],R[N],root[N];
LL Ans;
struct Segment_Tree
{
#define ls son[x][0]
#define rs son[x][1]
#define lson ls,l,m
#define rson rs,m+1,r
#define S N*20
int tot,sz[S],son[S][2];
LL sum[S];
#undef S
#define Update(x) sz[x]=sz[ls]+sz[rs], sum[x]=sum[ls]+sum[rs]
void Insert(int &x,int l,int r,int pos)
{
if(!x) x=++tot;
if(l==r) {sz[x]=1, sum[x]=pos; return;}
int m=l+r>>1;
pos<=m ? Insert(lson,pos) : Insert(rson,pos);
Update(x);
}
int Merge(int x,int y)
{
if(!x||!y) return x|y;
Ans-=sum[ls]*sz[rs]+sum[son[y][0]]*sz[son[y][1]];
ls=Merge(ls,son[y][0]), rs=Merge(rs,son[y][1]);
Ans+=sum[ls]*sz[rs], sz[x]+=sz[y], sum[x]+=sum[y];// Update(x); 不要写Update...(虽然这题能过)
return x;
}
}T;
inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-48,c=gc());
return now;
}
int Find(int x)
{
return x==fa[x]?x:fa[x]=Find(fa[x]);
}
void Merge(int x,int y)
{
x=Find(x), y=Find(y), fa[y]=x;
Ans-=T.sum[root[x]]*x+T.sum[root[y]]*y;
root[x]=T.Merge(root[x],root[y]);
Ans+=T.sum[root[x]]*x;
R[x]=R[y];
}
int main()
{
const int n=read();
for(int i=1; i<N; ++i) R[i]=i, fa[i]=i;
for(int i=1; i<=n; ++i)
{
int a=read(),b=read(),p=root[a]?R[Find(a)]+1:a;
Ans-=1ll*a*b, T.Insert(root[p],1,n,b), Ans+=1ll*p*b;
if(root[p-1]) Merge(p-1,p);
if(root[p+1]) Merge(p,p+1);
printf("%I64d\n",Ans);
}
return 0;
}
Codeforces.1051G.Distinctification(线段树合并 并查集)的更多相关文章
- BZOJ4399魔法少女LJJ——线段树合并+并查集
题目描述 在森林中见过会动的树,在沙漠中见过会动的仙人掌过后,魔法少女LJJ已经觉得自己见过世界上的所有稀奇古怪的事情了LJJ感叹道“这里真是个迷人的绿色世界,空气清新.淡雅,到处散发着醉人的奶浆味: ...
- Educational Codeforces Round 51 (Rated for Div. 2) G. Distinctification(线段树合并 + 并查集)
题意 给出一个长度为 \(n\) 序列 , 每个位置有 \(a_i , b_i\) 两个参数 , \(b_i\) 互不相同 ,你可以进行任意次如下的两种操作 : 若存在 \(j \not = i\) ...
- BZOJ2733[HNOI2012]永无乡——线段树合并+并查集+启发式合并
题目描述 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达 ...
- 洛谷P3224 [HNOI2012]永无乡(线段树合并+并查集)
题目描述 永无乡包含 nnn 座岛,编号从 111 到 nnn ,每座岛都有自己的独一无二的重要度,按照重要度可以将这 nnn 座岛排名,名次用 111 到 nnn 来表示.某些岛之间由巨大的桥连接, ...
- BZOJ4530 BJOI2014大融合(线段树合并+并查集+dfs序)
易知所求的是两棵子树大小的乘积.先建出最后所得到的树,求出dfs序和子树大小.之后考虑如何在动态加边过程中维护子树大小.这个可以用树剖比较简单的实现,但还有一种更快更优美的做法就是线段树合并.对每个点 ...
- 线段树合并+并查集 || BZOJ 2733: [HNOI2012]永无乡 || Luogu P3224 [HNOI2012]永无乡
题面:P3224 [HNOI2012]永无乡 题解: 随便写写 代码: #include<cstdio> #include<cstring> #include<iostr ...
- 2018.09.30 bzoj4025: 二分图(线段树分治+并查集)
传送门 线段树分治好题. 这道题实际上有很多不同的做法: cdq分治. lct. - 而我学习了dzyo的线段树分治+并查集写法. 所谓线段树分治就是先把操作分成lognlognlogn个连续不相交的 ...
- 【BZOJ2733】永无乡(线段树,并查集)
[BZOJ2733]永无乡(线段树,并查集) 题面 BZOJ 题解 线段树合并 线段树合并是一个很有趣的姿势 前置技能:动态开点线段树 具体实现:每次合并两棵线段树的时候,假设叫做\(t1,t2\), ...
- 洛谷P4121 [WC2005]双面棋盘(线段树套并查集)
传送门 先膜一下大佬->这里 据说这题正解是LCT,然而感觉还是线段树套并查集的更容易理解 我们对于行与行之间用线段树维护,每一行内用并查集暴力枚举 每一行内用并查集暴力枚举连通块这个应该容易理 ...
随机推荐
- HTML&javaSkcript&CSS&jQuery&ajax(十)
HTML 1.SVG直接嵌入HTML网页 ,SVG 是使用XML描述2D图像的语言,Canvas通过JavaScript来绘制2D <svg xmlns="http://www.w3. ...
- python操作注册表
#注册表操作 # -*- coding: utf-8 -*- import win32api import win32con #打开注册表:传主键化值,子键值,操作方法(win32con.KEY_AL ...
- Google C++ 代码规范
Google C++ Style Guide Table of Contents Header Files Self-contained Headers The #define Guard For ...
- 饮冰三年-人工智能-linux-09 服务
1:SSH服务(提供远程连接服务) 客户端使用Xshell 链接成功 加快连接速度 关闭防火墙 2:apache 服务(提供网页服务) 2.0 准备环境 关闭防火墙:service iptables ...
- 关于HTML或JS加密解密的七种方式
本文一共介绍了七种方法: 一:最简单的加密解密 二:转义字符""的妙用 三:使用Microsoft出品的脚本编码器Script Encoder来进行编码 (自创简 ...
- 从零开始学C#——不再更新,直接进入高阶教程
从零开始学习C#不再更新,直接进入高阶教程. 入门教程,请自行谷歌.百度吧,有很多这样的教程. 编程是一件实践性很强的事情,那么接下来的文章将开始进行开发项目. 还在编程中迷茫的人们,先暂时放下一切的 ...
- nunit单元测试详解
在粗略看了代码后,下面就详细说明相应的测试标记(属性)的用法. [TestFixture(arguments)]属性标记类为测试类,若没有填写参数,则测试类必须含有无参构造函数,否则需要相应的有参构造 ...
- WARN Session 0x0 for server null, unexpected error, closing socket connection and attempting reconnect (org.apache.zookeeper.ClientCnxn) java.net.ConnectException: Connection refused
1.启动kafka的脚本程序报如下所示的错误: [hadoop@slaver1 script_hadoop]$ kafka-start.sh start kafkaServer... [-- ::,] ...
- java.lang.NullPointerException at java.lang.ProcessBuilder.start(Unknown Source) at org.apache.hadoop.util.Shell.runCommand(Shell.java:482)
1:问题出现的原因,部署好的hadoop-2.6.4进行window10操作hadoop api出现的错误,具体错误是我向hdfs上传文件,还好点,之前解决过,这里不叙述,这里说一下从hdfs下载文件 ...
- sharepoint2013 Restore-SPSite 报错,采用数据库还原
PS C:\Users\spadmin> Restore-SPSite http://hz0xw002049:8099 -Path D:\20170731MossSiteSP.bak -Forc ...