首页 > 其他分享 >CF896E/洛谷 P4117 [Ynoi2018]五彩斑斓的世界/Welcome home, Chtholly

CF896E/洛谷 P4117 [Ynoi2018]五彩斑斓的世界/Welcome home, Chtholly

时间:2023-06-20 20:34:36浏览次数:54  
标签:P4117 Ynoi2018 洛谷 val sz int 复杂度 rt mod

分块。我们先来考虑修改对整块的影响。记值域为 \(V=10^5\)。

考虑对每一块维护 \(V\) 个集合 \(S_1,S_2,\cdots,S_V\),第 \(i\) 个集合 \(S_i\) 维护了区间中所有 \(=i\) 的元素的一些信息,并维护区间的最大值 \(m\),对于一次操作 \(x\):

  • 若 \(m\le 2x\),我们暴力对每个 \(i\in [x+1,m]\),将 \(S_i\) 合并进集合 \(S_{i-x}\)。
  • 若 \(m>2x\),那么操作相当于先把 \(\le x\) 的数 \(+x\),再做全局 \(-x\)。我们对每个 \(i\in[1,x]\),把 \(S_i\) 合并进 \(S_{i+x}\),然后再给这个块打上标记 \(x\),表示这个块实际上的 \(=i\) 的元素构成的集合应该是 \(S_{i+x}\)。

我们设一次合并的复杂度为 \(O(f(n))\),那么对于第一种情况,我们用 \(m-x\) 次操作使 \(m\) 减小了 \(m-x\);对于第二种情况,我们用 \(x\) 次操作使 \(m\) 减小了 \(x\)。由于 \(m\le V\) 且 \(m\) 单调递减,因此一块的复杂度不会超过 \(O(V\times f(n))\),总的复杂度就不超过 \(O(V\sqrt{n}\times f(n))\)。

考虑应当怎样维护这样的集合的合并。注意我们需要在散块处进行重构,还需要应对查询,因此我们的 \(S_i\) 应当满足:

  • 由 \(S_1,\cdots S_V\) 足以推出整个块的完整信息。
  • 可以查询某个集合的大小 \(|S_i|\)。

那么只需要维护 \(S_i=\{j|a_j=i\}\),即所有 \(=i\) 的元素位置即可。具体实现的时候,我们可以一开始把所有相同的数全都连到最先出现的位置上,并记录每种元素第一次出现的位置;同时我们维护每种元素第一次出现时的值。也就是说,我们维护的块中,(实际的序列中)每种元素第一次出现的位置(在我们维护的序列中)的值应当是正确的。

那么一次操作假设要把 \(x\) 合并到 \(y\) 上面,我们就找到 \(r_x,r_y\),讨论一下:

  • 如果 \(r_x\) 不存在那么什么都不用干。
  • 如果 \(r_y\) 不存在,那么我们令 \(r_y\leftarrow r_x\),然后令 \(\text{val}(r_x)\leftarrow y\),最后把 \(r_x\) 置为 \(0\)。
  • 否则我们找到 \(r_x,r_y\) 中较小的那一个 \(p\),令 \(\text{val}(p)\leftarrow y\),把 \(r_y\) 的父亲置为 \(p\),并令 \(r_x\leftarrow 0\)。

实际上这里维护的或许不能说是并查集,这更像一个链表,只不过是树形结构的。

如果要重构一块,由于我们保证了 \(i\) 的父亲在 \(i\) 前面,从前往后扫就行了。

直接做或许需要记录每一块的 \(r\) 序列导致空间复杂度达到 \(O(n\sqrt{n})\),考虑把询问全部离线,对每一块分别考虑他对所有修改与询问的贡献即可。这样空间复杂度就是线性,可以通过 P4117。

下面是 CF896E 的代码:

//-DYUNQIAN -std=c++14 -O2 -Wall
#include<bits/stdc++.h>

#define ll long long

using namespace std;

inline int read(){
	int x=0,f=1;char c=getchar();
	for(;(c<'0'||c>'9');c=getchar()){if(c=='-')f=-1;}
	for(;(c>='0'&&c<='9');c=getchar())x=x*10+(c&15);
	return x*f;
}

const int mod=1e9+7;
int ksm(int x,int y,int p=mod){
	int ans=1;
	for(int i=y;i;i>>=1,x=1ll*x*x%p)if(i&1)ans=1ll*ans*x%p;
	return ans%p;
}
int inv(int x,int p=mod){return ksm(x,p-2,p)%p;}
mt19937 rnd(time(0));
int randint(int l,int r){return rnd()%(r-l+1)+l;}
void add(int &x,int v){x+=v;if(x>=mod)x-=mod;}
void Mod(int &x){if(x>=mod)x-=mod;}

void Assert(bool c,int L=0){if(!c){cout<<"Assertion Failed at "<<L<<endl;exit(0);}}

const int N=2e5+5;
const int MX=1e5;
int rt[N],fa[N],sz[N],val[N];
void merge(int x,int y){
	if((!rt[x])||x>MX)return ;
	if(rt[y]){
		int p=min(rt[x],rt[y]);
		fa[rt[y]]=fa[rt[x]]=p,sz[p]=sz[rt[x]]+sz[rt[y]];
		if(rt[x]!=p)sz[rt[x]]=0;
		if(rt[y]!=p)sz[rt[y]]=0;
		val[p]=y,rt[y]=p,rt[x]=0;
	}
	else rt[y]=rt[x],val[rt[x]]=y,rt[x]=0;
}
int V,tag;
void build(int l,int r){
	V=0;
	for(int i=l;i<=r;i++){
		V=max(V,val[i]);
		if(rt[val[i]])fa[i]=rt[val[i]],sz[rt[val[i]]]++;
		else rt[val[i]]=i,sz[i]=1,fa[i]=i;
	}
}
void clear(int l,int r){
	for(int i=l;i<=r;i++)sz[rt[val[i]]]=0,rt[val[i]]=0,val[i]=val[fa[i]];
	for(int i=l;i<=r;i++)val[i]-=tag;
	tag=0;
}
void sub(int x){
	if(V-tag<=x)return ; 
	else if(V-tag<=x+x){for(int i=x+1;i<=V-tag;i++)merge(i+tag,i+tag-x);V=min(V,x+tag);}
	else{for(int i=1;i<=x;i++)merge(i+tag,i+tag+x);tag+=x;}
}

int op[N],st[N],ed[N],qv[N],n,m,a[N],ans[N];
int W=0;
void solve(int l,int r){
	for(int i=l;i<=r;i++)val[i]=a[i];tag=0;
	for(int i=1;i<=W;i++)rt[i]=sz[i]=0;
	build(l,r);
	for(int t=1;t<=m;t++){
		int ql=max(l,st[t]),qr=min(r,ed[t]),x=qv[t];
		if(ql>qr)continue;
		if(op[t]==1){
			if(ql==l&&qr==r)sub(x);
			else{
				clear(l,r);
				for(int i=ql;i<=qr;i++)if(val[i]>x)val[i]-=x;
				build(l,r);
			}
		}
		else{
			if(ql==l&&qr==r){ans[t]+=sz[rt[x+tag]];continue;}
			clear(l,r);
			for(int i=ql;i<=qr;i++)if(val[i]==x)ans[t]++;
			build(l,r);
		}
	}
}

signed main(void){

#ifdef YUNQIAN
	freopen("896E.in","r",stdin);
#endif

	n=read(),m=read();
	for(int i=1;i<=n;i++)a[i]=read(),W=max(W,a[i]);
	for(int i=1;i<=m;i++)op[i]=read(),st[i]=read(),ed[i]=read(),qv[i]=read();
	int B=(int)(sqrt(n));
	for(int i=1;i<=n;i+=B)solve(i,min(i+B-1,n));
	for(int i=1;i<=m;i++)if(op[i]==2)cout<<ans[i]<<'\n';

	return 0;
}

标签:P4117,Ynoi2018,洛谷,val,sz,int,复杂度,rt,mod
From: https://www.cnblogs.com/YunQianQwQ/p/17494613.html

相关文章

  • 洛谷 P8179 Tyres
    滴叉题/se/se题意直接复制了有\(n\)套轮胎,滴叉需要用这些轮胎跑\(m\)圈。使用第\(i\)套轮胎跑的第\(j\)圈(对每套轮胎单独计数)需要\(a_i+b_i(j-1)^2\)秒。滴叉需要进入维修站来更换轮胎,所消耗的时间为\(t\)秒。特别地,滴叉使用的第一套轮胎不需要进站更换。你需......
  • 洛谷P1578 奶牛浴场
    题目大意又是农夫约翰有一个$L\timesW$的矩阵,中间有$n$个障碍,你要框出面积最大的一块长方形,其中不能包含障碍。数据范围对于所有数据,\(0\len\le5\times10^3,1\leL,W\le3\times10^4\)题解首先,可以根据极大化思想设计一个基本算法:枚举上下左右四个边界......
  • 洛谷 P6821 [PA2012]Tanie linie
    洛谷传送门考虑恰好选\(k\)个子段怎么做。设恰好选\(i\)个子段的和最大值为\(h_k\)。可以得到\(h_{i+1}-h_i\leh_i-h_{i-1}\),因为\(h_i\toh_{i+1}\)的过程就是多选一个子段,贡献肯定不如上一次选即\(h_{i-1}\toh_i\)大。如果它不成立,那我们可以交换......
  • 洛谷P5322 [BJOI2019] 排兵布阵
    题目大意有s名对手,n座城堡,你有m名士兵如果一名玩家向第\(i\)座城堡派遣的士兵数严格大于对手派遣士兵数的两倍,那么这名玩家就占领了这座城堡,获得\(i\)分。求最大得分数据范围对于\(10\%\)的数据:\(s=1,n\le3,m\le10\)对于\(20\%\)的数据:\(s=1,n\le10,m\le1......
  • 【若归】 【LGR-142-Div.4】洛谷入门赛 #13赛后反思
    比赛链接:【LGR-142-Div.4】洛谷入门赛#13rk288,比前几次差(可能是因为rated?)A十年OI一场空,不开longlong见祖宗#include<bits/stdc++.h>usingnamespacestd;intmain(){ longlongintn; cin>>n; cout<<"8"<<12*(n-2)<<""<<6*(n-......
  • 洛谷 P6003 总结
    题目:洛谷P6003链接:洛谷,逐月题意有一个人欠了别人\(n\)单位牛奶,每一天他会还\(y=\max(m,\frac{n-g}{x})\)单位,\(g\)为之前还的牛奶,请求出最大的\(x\)使得这个人在\(k\)天后能换至少\(k\)单位牛奶。\(1\len,m,k\le10^{12},km<n\)。思路暴力......
  • 【LGR-141-Div.2】洛谷 6 月月赛 I (前两题)
    T1:金盏花传送门直接暴力枚举前6位的值即可,记得开longlong#include<bits/stdc++.h>usingnamespacestd;#defineintlonglonginty,z,ans=1e18;signedmain(){ scanf("%lld%lld",&y,&z); for(inti=100000;i<=999999;i++){ intx=i*1000000+y; ans=min......
  • 洛谷P1587 [NOI2016] 循环之美
    原文链接:[sol]P1587[NOI2016]循环之美-icyM3tra'sBlog此为备份。题目传送门0.前言提供一种式子较为简洁且不算难写的做法。以及介绍一种较为优秀的dp版杜教筛实现。1.式子推导我们知道纯循环小数一定可以写成分母形如\(k^a-1\)的分数。因此约分后的分母一定......
  • 洛谷 P3723 [AH2017/HNOI2017]礼物
    由题面可得:\[E_j=\sum_{i=1}^{j-1}\frac{q_i}{(i-j)^2}-\sum_{i=j+1}^{n}\frac{q_i}{(i-j)^2}\]令\(q_0=0\),并将没有意义的分式的值视为\(0\),则有:\[E_j=\sum_{i=0}^j\frac{q_i}{(i-j)^2}-\sum_{i=j}^n\frac{q_i}{(i-j)^2}\]令\(A(i)......
  • 海底高铁(洛谷3406)
         #include<iostream>usingnamespacestd;constintN=100010;intp[N];//要去的城市intA[N],B[N],C[N];longlongs,ans[N];//ans差分数组intmain(){intN,M;scanf("%d%d",&N,&M);for(inti=1;i<=M......