首页 > 其他分享 >《CF gym Reverse LIS》解题报告

《CF gym Reverse LIS》解题报告

时间:2023-10-06 20:13:27浏览次数:37  
标签:Reverse int gym CF long ls 权值 itv LL

原题链接

一开始看到这题就很像模拟费用流,不过立马就放弃了,然后之后就再也没想过这个思路了。。。

正解是模拟费用流,先讲一下答案长什么样,把 \(0\) 的权值记为 \(1\) , \(1\) 的权值记为 \(-1\) ,那么我们答案就是要选一段前缀和 \(k\) 段不相交的区间的最大值加上 \(1\) 的个数。

考虑为什么是 \(k\) 段不相交的区间,因为我们是区间翻转,所以一定能通过 \(k\) 次区间翻转,将前缀和这 \(k\) 段区间拼在一起。

然后 \(1\) 的权值记为 \(-1\) ,这是比较巧妙的一个点,这样你选的 \(0\) 间的 \(1\) 一定是无法造成贡献的,而我们把这些 \(1\) 的贡献减掉,最后加上所有 \(1\) 的贡献,很好的对应上了我们决策的方法,然后这题就做完了。

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

点击查看代码
#include<bits/stdc++.h>
#define int long long
typedef long long LL;

using namespace std;
const int MAXN=2e5+10;
const LL inf=1e18;
int n;
struct itv {
	LL l,r,s;
};
itv operator +(itv x,itv y) {
	return {x.l,y.r,x.s+y.s};
}
bool operator <(itv x,itv y) {
	return x.s<y.s;
}
struct ddl {
	itv sum;
	itv smi,smx;
	itv lmi,rmi,lmx,rmx;
	bool rev;
}tr[(MAXN<<2)];
void neww(int u,int x,int y) {
	tr[u].smx=
	tr[u].smi=
	tr[u].lmi=
	tr[u].rmi=
	tr[u].lmx=
	tr[u].rmx=
	tr[u].sum={x,x,y};
}
ddl merge(ddl x,ddl y) {
	ddl z;
	z.smx=max(x.smx,y.smx);
	z.smx=max(z.smx,x.rmx+y.lmx);
	z.smi=min(x.smi,y.smi);
	z.smi=min(z.smi,x.rmi+y.lmi);
	z.lmx=max(x.lmx,x.sum+y.lmx);
	z.rmx=max(y.rmx,x.rmx+y.sum);
	z.lmi=min(x.lmi,x.sum+y.lmi);
	z.rmi=min(y.rmi,x.rmi+y.sum);
	z.sum=x.sum+y.sum;
	z.rev=0;
	return z;
}
void clere(int u) {
	swap(tr[u].lmi,tr[u].lmx);
	swap(tr[u].rmi,tr[u].rmx);
	swap(tr[u].smi,tr[u].smx);
	tr[u].lmi.s*=-1; tr[u].lmx.s*=-1;
	tr[u].rmi.s*=-1; tr[u].rmx.s*=-1;
	tr[u].smi.s*=-1; tr[u].smx.s*=-1;
	tr[u].sum.s*=-1;
	tr[u].rev^=1;
}
void psdn(int u) {
	if(tr[u].rev) {
		clere((u<<1));
		clere((u<<1|1));
		tr[u].rev=0;
	}
}
void rev(int u,int l,int r,int x,int y) {
	if(l>=x&&r<=y) {
		clere(u);
		return ;
	}
	int mid=(l+r)/2;
	psdn(u);
	if(x<=mid) rev((u<<1),l,mid,x,y);
	if(y>mid) rev((u<<1|1),mid+1,r,x,y);
	tr[u]=merge(tr[(u<<1)],tr[(u<<1|1)]);
}
void update(int u,int l,int r,int x,int y) {
	if(l==r) {
		neww(u,x,y);
		return ;
	}
	int mid=(l+r)/2;
	psdn(u);
	if(x<=mid) update((u<<1),l,mid,x,y);
	else update((u<<1|1),mid+1,r,x,y);
	tr[u]=merge(tr[(u<<1)],tr[(u<<1|1)]);
}
int idx[MAXN],idy[MAXN],tot;
ddl query(int u,int l,int r,int x,int y) {
	if(l>=x&&r<=y) return tr[u];
	int mid=(l+r)/2;
	psdn(u);
	if(y<=mid) return query((u<<1),l,mid,x,y);
	else if(x>mid) return query((u<<1|1),mid+1,r,x,y);
	else return merge(query((u<<1),l,mid,x,y),query((u<<1|1),mid+1,r,x,y));
}
LL ans[MAXN];
signed main () {
	scanf("%lld",&n);
	LL ls=0,pp=0,j=0,da=0;
	for(int i=1;i<=n;++i) {
		LL oo=0,nu=0;
		scanf("%lld%lld",&oo,&nu);
		if(oo==0) {
			update(1,1,n,i,nu);
			pp+=nu;
		}
		else {
			pp-=nu;
			update(1,1,n,i,-nu);
			ls+=nu;
		}
		if(pp>da) {
			da=pp;
			j=i;
		}
	}
	ans[0]=da+ls;
	if(j) rev(1,1,n,1,j);
	for(int i=1;i<=n;++i) {
		ddl ls=query(1,1,n,1,n);
		ans[i]=ans[i-1];
		if(ls.smx.s>=0) {
			ans[i]+=ls.smx.s;
			rev(1,1,n,ls.smx.l,ls.smx.r);
		}
	}
	LL Q;
	scanf("%lld",&Q);
	for(int i=1;i<=Q;++i) {
		LL x;
		scanf("%lld",&x);
		printf("%lld\n",ans[x]);
	}
	return 0;
}

标签:Reverse,int,gym,CF,long,ls,权值,itv,LL
From: https://www.cnblogs.com/ddl1no2home/p/17744927.html

相关文章

  • [题解] CF1245D - Shichikuji and Power Grid
    CF1245D-ShichikujiandPowerGrid题目传送门题意在一个网格图中,有\(n\)个城市。目标是使得\(n\)个城市都通电。对于一个城市有电,要么选择在其位置建立发电站,要么和另一个有电的城市连线。对于城市\(i\),在其位置建立发电站的费用为\(c_i\),和另一个城市\(j\)连电......
  • 《CF1824E LuoTianyi and Cartridge》 解题报告
    好题。模拟赛出了这题,抽象。初步化简:由于\(\min(A,C)\)不好处理,我们考虑从大到小加边加点,或者从小到大删边删点。一般题目是考虑加边加点好操作一点,这题是考虑删边删点好操作。然后我们记当前枚举的\(\min(A,C)\)的最小值是多少,记为\(x\)。然后称大于等于\(x\)点权......
  • CF1878E Iva & Pav
    思路要求从一个点开始最远可以选择那个点使得两点之间的数字的与大于等于\(k\),最开始想到的是提前预处理出每个点往后若干位的与,因为与只可能变小不可能变大,所以可以二分找到最远的位置,但是这样无论时间还是空间都会爆掉,所以我们考虑优化一下这个办法。既然不能把每个点的后面......
  • CF1010C Border 题解
    题目传送门前置知识最大公约数|裴蜀定理简化题意给定一个长度为\(n\)的序列\(a\),求能用\(r=(\sum\limits_{i=1}^{n}d_ia_i)\bmodk\)表示的不同的\(r\)的个数及所有情况,其中对于每一个\(i(1\lei\len)\)均有\(d_i\)为非负整数。解法依据裴蜀定理,不难得到存......
  • CF131D Subway 题解
    题目传送门前置知识强连通分量|最短路解法考虑用Tarjan进行缩点,然后跑最短路。缩点:本题的缩点有些特殊,基于有向图缩点修改而得,因为是无向图,所以在Tarjan过程中要额外记录一下从何处转移过来,防止在同一处一直循环。基环树上找环还有其他方法,这里仅讲解使用Tarjan求......
  • cf1110D. Jongmah
    cf1110D.Jongmah如果能够发现一点转化的话就简单很多比如说最后的答案里出现了三个(a,a+1,a+2),我们可以将它看作是(a,a,a),(a+1,a+1,a+1),(a+2,a+2,a+2)也就是每种三元组(除了(a,a,a))最多只会出现两次那么每种数最多有6个是个其它数组成三元组。直接dp即可#include<cstdio>#......
  • 【bitset】【线段树】CF633G Yash And Trees 题解
    CF633G简单题。先看到子树加和子树质数个数和,果断转换为dfs序进行处理。既然有区间求和,考虑线段树。若对于每一个节点维护一个\(cnt\)数组,用二进制数\(x\)来表示,即当\(cnt_i=1\)时第\(i\)位为\(1\)。设当前节点为\(u\),左右子节点分别为\(ls\)和\(rs\)。发现......
  • 【线段树合并】CF1805E There Should Be a Lot of Maximums 题解
    CF1805E待补:有另解看到维护树上问题,可以想到线段树合并。但直接维护显然不行,要一点技巧。发现\(val\)的出现次数\(cnt_{val}\)如果\(\ge3\),那么一定是一个候选项,若\(cnt_{val}=1\),那么一定不能作为候选项。于是可以用权值线段树维护对于\(val\)有\(cnt_{val}=......
  • 【图论】【寻找性质】CF1151E Number of Components 题解
    CF1151E发现每一个\(f(l,r)\)中的连通块总是一条链(一棵树)。那么此时连通块的数量就等于点的数量减去边的数量。先考虑点的总数,一个价值为\(a_i\)的点一定是在\(l\leqslanta_i\)且\(r\geqslanta_i\)的\(f(l,r)\)中才会有一个贡献,根据乘法原理,它会产生\(a_i\time......
  • 报错AttributeError: Attempted to set WANDB to False, but CfgNode is immutable
    问题 今天在跑代码的时候,使用到了wandb记录训练数据。 我在23服务器上跑的好好的,但将环境迁移到80服务器上重新开始跑时,却遇到了如下报错 看这个报错信息是由于wandb没有apis这个属性,于是我定位到具体的报错代码 ......