首页 > 其他分享 >CF1862G 题解

CF1862G 题解

时间:2024-02-27 18:25:05浏览次数:26  
标签:cur int 题解 CF1862G treap ls ans New

首先这个查询操作很迷,考虑先化简查询操作。

不难发现由于每次是加上一个逆的等差序列,因此一次操作完每个数与它的前驱之差一定会减少,因此加上等差序列的次数就等于全局每个数与它的前驱之差最大值。

又因为会排序去重,所以最后剩下来的数一定是最开始的数一路加过来的,至此我们发现答案就是全局每个数与它的前驱之差最大值加上全局最大值。

考虑怎么维护这个东西,显然可以使用 FHQ treap 维护这件事,我们需要维护子树最大差,最小值,最大值就可以合并信息,在点修时先把原来的数删掉,在插入新的数。

时间复杂度 \(O(n \log n)\)。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5+114;
int n,q;
int a[maxn];
struct Node{
	int val,ls,rs,w,mx,mi,ans;
}treap[maxn];
stack<int> brush;
int tot;
int rt;
int clone(int w){
	int New;
    if(brush.size()>0) New=brush.top(),brush.pop();
    else New=++tot;
	treap[New].val=rand();
	treap[New].ls=0;
	treap[New].rs=0;
	treap[New].w=w;
	treap[New].mi=treap[New].mx=w;
	treap[New].ans=0;
	return New;
}
inline void pushup(int cur){
	treap[cur].ans=0;
	treap[cur].ans=max(treap[treap[cur].ls].ans,treap[treap[cur].rs].ans);
	if(treap[cur].ls!=0) treap[cur].ans=max(treap[cur].w-treap[treap[cur].ls].mx,treap[cur].ans);
	if(treap[cur].rs!=0) treap[cur].ans=max(treap[treap[cur].rs].mi-treap[cur].w,treap[cur].ans);
	treap[cur].mx=treap[cur].mi=treap[cur].w;
	if(treap[cur].rs!=0) treap[cur].mx=treap[treap[cur].rs].mx;
	if(treap[cur].ls!=0) treap[cur].mi=treap[treap[cur].ls].mi;
}
inline int merge(int x,int y){
    if(!x||!y) return x+y;
    if(treap[x].val<treap[y].val){
        treap[x].rs=merge(treap[x].rs,y);
        pushup(x);
        return x;
    }
    else{
        treap[y].ls=merge(x,treap[y].ls);
        pushup(y);
        return y;
    }
}
inline void split(int cur,int x,int &l,int &r) {
	if(cur==0){
		l=r=0;
		return ;
	}
	if(treap[cur].w>x){
		r=cur;
		split(treap[cur].ls,x,l,treap[cur].ls);
	}
	else{
		l=cur;
		split(treap[cur].rs,x,treap[cur].rs,r);
	}
	pushup(cur);
}
void dfs(int u){
	if(u==0) return ;
	dfs(treap[u].ls);
	cout<<treap[u].w<<' '<<treap[u].mx<<' '<<treap[u].mi<<'\n';
	dfs(treap[u].rs);
}
void insert(int w){
	int x=0,y=0,z=0;
	split(rt,w,x,z);
	y=clone(w);
	rt=merge(x,merge(y,z));
}
void erase(int w){
	int x=0,y=0,z=0;
	split(rt,w-1,x,y);
	split(y,w,y,z);
    brush.push(y);
	y=merge(treap[y].ls,treap[y].rs);
	rt=merge(x,merge(y,z));
}
void work(){
	rt=tot=0;
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		insert(a[i]); 
	}
	cin>>q;
	while(q--){
		int x,y;
		cin>>x>>y;
		erase(a[x]);
		a[x]=y;
		insert(a[x]);
		cout<<treap[rt].mx+treap[rt].ans<<' ';
	}
	cout<<'\n';
}
int T;
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin>>T;
	while(T--)work();
}

标签:cur,int,题解,CF1862G,treap,ls,ans,New
From: https://www.cnblogs.com/chifan-duck/p/17998341

相关文章

  • P5837 [USACO19DEC] Milk Pumping G 题解
    原题传送门思路只用堆每一个点跑一边最短路,在用当前点到点\(n\)的距离,再用当前点的\(f\)乘上\(10^6\)除以刚刚算出的值即可。代码#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<vector>#include<queue>usingnamespacestd;#defin......
  • P2350 [HAOI2012] 外星人 题解
    很巧妙的一道题。首先会发现如果最终\(\varphi(N)=1\)的话一定是通过很多次从\(2\)这个因子变到\(1\)的。而这个函数每迭代一次,就会有且仅有一个\(2\)的因子变为\(1\)。所以题目转化为了求\(N\)在函数迭代过程中一共会产生多少个\(2\)的因子。考虑\(\text{dp}\),设......
  • U332154 carbon 题解(期望)
    这题其实挺简单的......首先我们手模样例,对于第一组样例其实就是在1-n之间取一个数,求取到的数的期望。所以E(x)=\(\frac{1+n}{2}\)。对于第二组样例,我们首先将所有可能情况枚举出来:1010101010101010101099999999910888888889......
  • U329011 trie pi 题解
    花了2d打磨出来的题目,觉得很有意思。先讲点无关的,这道题有两版,但都是对要求的量进行改动。1.第一次要求的是y属性为a与y属性为b的两个节点的路径权值之和,对于要求的这个量,我们设v[i]为i到根节点的权值之和。那么我们先对a,b进行质因数分解,设dcg为a,b分解质因数后最长公共前缀的乘......
  • 时间戳时区问题解决方法
    在大家开发时会遇到这种情况:服务器是以东八时区为准(即中国标准时间),但是客户端会在不同地方,比如说雅典开罗(+2),格陵兰(-3),夏威夷(-10),当客户端选择某一个时间后,传递给服务器的时间戳,是以当地时区来解析的时间戳,这样就会出现一个时间差的问题,从而造成时间不准确。下面我们就来解决这种问......
  • [ABC314Ex] Disk and Segments题解(退火实现)
    一到比较水的退火题(虽然也调了3h)题意在平面直角坐标系中,有\(n\)条线段,第\(i\)条的端点是\((a_i,b_i)\)和$(c_i,d_i)$,任意线段不共点。(这里笔者为了方便会默认\(a_i<c_i\))你要在平面上画一个圆,使得任意一条线段都和圆周或圆内部有至少一个公共点,求满足条件的圆的最小......
  • P4666 [BalticOI 2011 Day1] Growing Trees题解(平衡树思想)
    自己第一道不看题解写出来的紫题,庆祝一下(没初始化种子导致调了30min)这是一个fhq-treap的题解思路来源:首先看题目,因为是序列上的问题,不难想到是一道数据结构题。首先看到操作C:对于这种操作,我们可以用平衡树解决,具体方法是,将树split成\(<min,min\lex\lemax,>max\)这......
  • AGC005D 题解
    传送门如果一个排列\(P\)满足对于所有的\(i\)都有\(|P_i-i|\neqk\),则称排列\(P\)为合法的。现给出\(n\)和\(k\),求有多少种合法的排列。由于答案很大,请输出答案对\(924844033\)取模的结果。\(2\leqn\leq2\times10^3\),\(1\leqk\leqn-1\)。一个新的trick:考虑......
  • 2024.2.25模拟赛T3题解
    题目推出dp柿子之后,枚举\(i\)的时候用线段树维护\(1-i\)的\(mex\)段,对于每一段,分别使用线段树套李超树维护,对于每个\(mex\)再次使用线段树套李超树维护即可code#include<bits/stdc++.h>usingnamespacestd;#defineN600005#defineintlonglongintn,m;consti......
  • 2024.2.25模拟赛T1题解
    题目考虑DP式子之后,可以通过堆维护函数,求出对应值code#include<bits/stdc++.h>usingnamespacestd;#defineintlonglong#defineN200005intzu,n,d,tg,num;inta[N];priority_queue<int>q;signedmain(){ scanf("%lld",&zu); while(zu--){ scanf(&qu......