首页 > 其他分享 >P7230 题解

P7230 题解

时间:2024-09-09 18:26:12浏览次数:10  
标签:P7230 int 题解 nd sgt tp st res

P7230

思路

对每个左端点维护右端点 \(res_i\)。操作形如删去一个数再加入一个数。如果删掉 \(p\) 上的 \(a_p\),找到左右最近的 \(l,r\) 使得 \(a_l=a_r=a_p\)。那么 \(res_{l+1},\dotsb,res_p\) 对 \(r\) 取 max。实际上要维护 \(\max res_i-i+1\),因为 \(res_i\) 单调,所以相当于线段树上二分找到最左的小于 \(r\) 的位置然后区间覆盖。

删除好做,加入难做,考虑线段树分治。先把所有的时刻的 \(a_i\) 都当作存在,右移右端点维护出所有 \(res_i\)。 multiset 维护每个值出现的位置来求 \(l,r\)。进入一个区间后进行删除操作。撤销操作可以用主席树,也可以记录下所有修改和下传的位置和值。

code

int n,m,q,a[maxn];
multiset<int> s[maxn];
int que[maxn],res[maxn],cnt[maxn];
vector<int> val[maxn];
int st[maxn<<6][4],tp;
#define mid (l+r>>1)
#define ls nd<<1
#define rs nd<<1|1
namespace sgt{
	int mx[maxn<<2],tag[maxn<<2],ans[maxn<<2];
	void build(int nd,int l,int r){
		if(l==r){
			mx[nd]=res[l];ans[nd]=mx[nd]-l+1;
			return ;
		}
		build(ls,l,mid),build(rs,mid+1,r);
		mx[nd]=max(mx[ls],mx[rs]),ans[nd]=min(ans[ls],ans[rs]);
	}
	void down(int nd,int l,int r){
			st[++tp][0]=nd,st[tp][1]=mx[nd],st[tp][2]=tag[nd],st[tp][3]=ans[nd];
		st[++tp][0]=ls,st[tp][1]=mx[ls],st[tp][2]=tag[ls],st[tp][3]=ans[ls];
		mx[ls]=tag[nd],tag[ls]=tag[nd],ans[ls]=mx[ls]-mid+1;
		st[++tp][0]=rs,st[tp][1]=mx[rs],st[tp][2]=tag[rs],st[tp][3]=ans[rs];
		mx[rs]=tag[nd],tag[rs]=tag[nd],ans[rs]=mx[rs]-r+1;
		tag[nd]=0;
	}
	void updata(int nd,int l,int r,int ql,int qr,int w){
		if(ql>qr)return ;
		if(l>=ql&&r<=qr){
			st[++tp][0]=nd,st[tp][1]=mx[nd],st[tp][2]=tag[nd],st[tp][3]=ans[nd];
			mx[nd]=w,tag[nd]=w,ans[nd]=mx[nd]-r+1;
			return ;
		}
		if(tag[nd])down(nd,l,r);
		if(ql<=mid)updata(ls,l,mid,ql,qr,w);
		if(qr>mid)updata(rs,mid+1,r,ql,qr,w);
		st[++tp][0]=nd,st[tp][1]=mx[nd],st[tp][2]=tag[nd],st[tp][3]=ans[nd];
		mx[nd]=max(mx[ls],mx[rs]),ans[nd]=min(ans[ls],ans[rs]);
	}
	int fd(int nd,int l,int r,int w){
		if(mx[nd]<w)return -1;
		if(l==r)return l;
		if(tag[nd])down(nd,l,r);
		int val=fd(ls,l,mid,w);
		if(val==-1)return fd(rs,mid+1,r,w);
		return val;
	}
}
vector<pii> tree[maxn<<2];
void updata(int nd,int l,int r,int ql,int qr,pii w){
	if(ql>qr)return ;
	if(l>=ql&&r<=qr){
		tree[nd].pb(w);
		return ;
	}
	if(ql<=mid)updata(ls,l,mid,ql,qr,w);
	if(qr>mid)updata(rs,mid+1,r,ql,qr,w);
}
void add(pii p){
	int l=*--s[p.se].find(p.fi);
	auto it=s[p.se].erase(s[p.se].find(p.fi));
	if(it==s[p.se].end()){
		sgt::updata(1,1,n,l+1,n,inf);
		return ;
	}
	int r=*it;
	int pos=sgt::fd(1,1,n,r);
	if(pos>l+1)sgt::updata(1,1,n,l+1,pos-1,r);
}
void del(){
	int nd=st[tp][0];
	sgt::mx[nd]=st[tp][1],sgt::tag[nd]=st[tp][2],sgt::ans[nd]=st[tp][3];
	tp--;
}
void dfs(int nd,int l,int r){
	int tmp=tp;
	for(pii p:tree[nd])add(p);
	if(l==r){
		if(que[l])printf("%lld\n",sgt::ans[1]>n?-1:sgt::ans[1]);
	}
	else{
		dfs(ls,l,mid),dfs(rs,mid+1,r);
	}
	while(tp>tmp)del();
	for(pii p:tree[nd])s[p.se].insert(p.fi);
}
void work(){
	n=read();m=read();q=read();
	for(int i=1;i<=n;i++)a[i]=read(),s[a[i]].insert(i),val[i].pb(a[i]);
	for(int i=1;i<=m;i++)s[i].insert(0);
	for(int i=1;i<=q;i++){
		int op=read();
		if(op==1){
			int p=read(),v=read();
			updata(1,1,q,i,q,{p,a[p]});
			a[p]=v;s[a[p]].insert(p);val[p].pb(a[p]);
			updata(1,1,q,1,i-1,{p,a[p]});
		}
		else que[i]=1;
	}
	for(int i=1,j=1,num=0;i<=n;i++){
		while(j<=n&&num<m){
			for(int k:val[j]){
				if(!cnt[k])++num;
				cnt[k]++;
			}
			j++;
		}
		if(num<m)res[i]=inf;
		else res[i]=j-1;
		for(int k:val[i]){
			cnt[k]--;
			if(!cnt[k])--num;
		}
	}
	sgt::build(1,1,n);
	dfs(1,1,q);
}

标签:P7230,int,题解,nd,sgt,tp,st,res
From: https://www.cnblogs.com/yhddd/p/18405064

相关文章

  • 【题解】Solution Set - NOIP2024集训Day25 概率期望 dp
    【题解】SolutionSet-NOIP2024集训Day25概率期望dphttps://www.becoder.com.cn/contest/5515「QOJ2606」Gachapon\(f_{i,j}\):用一次合法的level-irolling能够抽到的\(j\)的期望个数。\(h_{i,j,k}\):在\(i\)次操作之内,抽到恰好\(k\)个\(j\)的概率。\[h_{i,j,k......
  • luogu4198题解
    随机说话这个题做法没见过记一下。我一开始以为是李超树的题,结果把李超树打上之后就不会做了。然后题读错了写了一个弱化版。题目分析做法参考这个题题意只是假装是一个有关线段的题。简化之后的题意如下。有一个初始都为\(0\)的实数数列,每一次会修改位置\(x\)的数为......
  • Flutter 3.24 构建 release 抛出部分依赖 AAPT: error: resource android:attr/lStar
    问题截图:一些讨论:https://github.com/transistorsoft/flutter_background_fetch/issues/369问题原因及解决方案:@Aziz-T该问题与插件的compileSdkVersion和targetSdkVersion有关。出现该问题的原因是部分插件的compileSdkVersion和targetSdkVersion版本过旧。请前往......
  • P2471 [SCOI2007] 降雨量 题解
    题目传送门分析分讨题。首先发现是RMQ问题(区间最值),可以用线段树或ST表来维护(代码为线段树,因为我忘记ST表怎么写了)。然后发现有些年份不明确导致区间判断似乎不好搞。但事实上只要判断下标差是否等于年份差即可得出该区间有无不明确年份。其次考虑“必真”,“必假”,“......
  • 【洛谷 P1996】约瑟夫问题 题解(数组+模拟+循环)
    约瑟夫问题题目描述个人围成一圈,从第一个人开始报数,数到的人出列,再由下一个人重新从开始报数,数到的人再出圈,依次类推,直到所有的人都出圈,请输出依次出圈人的编号。注意:本题和《深入浅出-基础篇》上例题的表述稍有不同。书上表述是给出淘汰名小朋友,而该题是全部出圈。输入......
  • 题解 GZOI2023D2B【乒乓球】
    4s,512M题目描述Alice和Bob在打乒乓球,乒乓球比赛的规则是这样的:一场比赛中两位选手将进行若干局比赛,选手只需要赢得\(X\)局比赛就宣告其胜利;每局比赛中两位选手将进行若干盘比赛,选手只需要赢得\(Y\)盘比赛就宣告其胜利;每盘比赛中两位选手将进行乒乓球对决,有且仅有一位选......
  • AtCoder Beginner Contest 274 A~E 题解
    吐槽:这比赛名字为啥没有英文版。。。A-BattingAverage题目大意给定整数\(A,B\),输出\(\fracBA\),保留三位小数。\(1\leA\le10\)\(0\leB\leA\)分析签到题,使用printf或cout格式化输出即可。代码#include<cstdio>usingnamespacestd;intmain(){ inta,b; sc......
  • TOYOTA MOTOR CORPORATION Programming Contest 2023#1 (AtCoder Beginner Contest 29
    好久没写题解了,这就来水一篇。A-JobInterview题目大意给定一个长为\(N\)的字符串\(S\),由o、-、x组成。判断\(S\)是否符合下列条件:\(S\)中至少有一个o。\(S\)中没有x。\(1\leN\le100\)分析签到题。直接按题意模拟即可。代码#include<cstdio>usingn......
  • AtCoder Beginner Contest 318 G - Typical Path Problem 题解
    G-TypicalPathProblem题目大意给定一张\(N\)个点、\(M\)条边的简单无向图\(G\)和三个整数\(A,B,C\)。是否存在一条从顶点\(A\)到\(C\),且经过\(B\)的简单路径?数据范围:\(3\leN\le2\times10^5\)\(N-1\leM\le\min(\frac{N(N-1)}2,2\times10^5)\)\(1\leA......
  • UNIQUE VISION Programming Contest 2023 Christmas (AtCoder Beginner Contest 334)
    A-ChristmasPresent题目大意给定两个正整数\(B,G\)(\(1\leB,G\le1000\)且\(B\neG\)),判断哪个更大。分析模拟即可。代码#include<cstdio>usingnamespacestd;intmain(){ intb,g; scanf("%d%d",&b,&g); puts(b>g?"Bat":&qu......