题目链接


\(Description\)

给定\(n\)个数对\(A_i,B_i\)。你可以进行任意次以下两种操作:

  1. 选择一个位置\(i\),令\(A_i=A_i+1\),花费\(B_i\)。必须存在一个位置\(j\),满足\(A_i=A_j,\ i\neq j\),才可以进行。
  2. 选择一个位置\(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*20int 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;
}

转载于:https://www.cnblogs.com/SovietPower/p/10374029.html

Codeforces.1051G.Distinctification(线段树合并 并查集)相关推荐

  1. BZOJ4399魔法少女LJJ——线段树合并+并查集

    题目描述 在森林中见过会动的树,在沙漠中见过会动的仙人掌过后,魔法少女LJJ已经觉得自己见过世界上的所有稀奇古怪的事情了 LJJ感叹道"这里真是个迷人的绿色世界,空气清新.淡雅,到处散发着醉 ...

  2. CodeForces - 1217F Forced Online Queries Problem(线段树分治+并查集撤销)

    题目链接:点击查看 题目大意:给出 nnn 个点,初始时互相不存在连边,需要执行 mmm 次操作,每次操作分为两种类型: 1xy1 \ x \ y1 x y:如果 (x,y)(x,y)(x,y) 之间 ...

  3. 牛客多校8 - All-Star Game(线段树分治+并查集按秩合并的撤销操作)

    题目链接:点击查看 题目大意:有 n 个球员和 m 个球迷,一个球员可能是多个球迷的粉丝,需要选择最少的球员进行比赛,使得所有的球迷都愿意观看(对于每个球迷来说,都有至少一个其喜欢的球员入选比赛) 对 ...

  4. Codeforces 1140F 线段树 分治 并查集

    题意及思路:https://blog.csdn.net/u013534123/article/details/89010251 之前cf有一个和这个相似的题,不过那个题只有合并操作,没有删除操作,直接 ...

  5. [NOI2018] 归程(线段树维护并查集的可持久化/kruskal重构树,倍增+dijkstra最短路)

    [NOI2018] 归程 description solution1 code1 solution2 code description 题目描述 本题的故事发生在魔力之都,在这里我们将为你介绍一些必要 ...

  6. bzoj4025-二分图【线段树分治,并查集】

    正题 题目链接:https://darkbzoj.tk/problem/4025 题目大意 nnn个点mmm条边,每条边会在一个TTT以内的时间段内出现,对于任意一个TTT以内的时刻求图是否是一个二分 ...

  7. 越野赛车问题——线段树分治+并查集

    题目 [题目描述] 小 $H$ 是一位优秀的越野赛车女选手.现在她准备在 $A$ 山上进行赛车训练. $A$ 山上一共有 $n$ 个广场,编号依次为 $1$ 到 $n$ ,这些广场之间通过 $n-1$ ...

  8. BZOJ 1018: [SHOI2008]堵塞的交通traffic(线段树分治+并查集)

    传送门 解题思路 可以离线,然后确定每个边的出现时间,算这个排序即可.然后就可以线段树分治了,连通性用并查集维护,因为要撤销,所以要按秩合并,时间复杂度\(O(nlog^2 n)\) 代码 #incl ...

  9. c++自带的可持久化平衡树?rope大法好!(超详细解答 + 5道例题讲解,可直接替代可持久化的线段树、并查集、平衡树!)

    整理的算法模板合集: ACM模板 目录 c++自带的可持久化平衡树?rope大法好! 1. 声明 2. 支持操作 char类型的rope int类型的rope 3. 具体的细节 4. "可持 ...

最新文章

  1. 数据拆分缺点和解决方案
  2. django中间件及中间件实现的登录验证
  3. python实现一对一聊天_vue+django实现一对一聊天功能
  4. iOS平台软件开发工具(一)-新建的工程使用CocoaPods工具集成第三方框架
  5. download plugin update site for offline installation
  6. StringUtils 中 isEmpty 和 isBlank 的区别
  7. 如何获取查询生成器以字符串形式输出其原始SQL查询?
  8. java split 实现_PL/SQL实现JAVA中的split()方法的例子
  9. python网络爬虫项目——翻译英文单词
  10. 什么是Cisco ACI?
  11. 一丶exit(1)丶exit(0)和return的区别
  12. park,clark和ipark浅析
  13. 【每日蓝桥】14、一三年省赛Java组真题“三部排序”
  14. android之animator 和animation 的区别
  15. python 调用easydl接口
  16. VisionPro通过SN码连接相机
  17. 第一篇:基于小米手机的,解锁教程教学
  18. 接手了一座年收入 2000 万美元的“屎山”,我到底该重写还是跳槽?
  19. 关于无符号相减得负数的问题
  20. 逻辑回归梯度下降推导

热门文章

  1. java listt add_Java8 使用流抽取ListT集合中T的某个属性操作
  2. 二本学校考211计算机,普通二本学校的学生考211/985的研究生真的很难吗?
  3. linux 修改密码和端口号_WINDOWS/LINUX系统修改管理员密码方法
  4. AcWing 143. 最大异或对
  5. vs查询mysql返回数据_vs与数据库连接查询
  6. C语言把输入值放入数组,//从键盘上输入若干整数,并将其存入数组中,并统计输入数据的个...
  7. [Hive]Hive常用的优化方法
  8. Apache OpenNLP(二)
  9. WPF学习:3.Border Brush
  10. 关于PCI-E接口你要知道这些点