【CF643G】 Choosing Ads(线段树)

传送门


区间绝对众数的线性做法拓展成区间合并,懒得写题解了。


代码:

#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const

namespace IO{
	inline char gc(){
		static cs int Rlen=1<<22|1;
		static char buf[Rlen],*p1,*p2;
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++; 
	}
	
	template<typename T>
	inline T get(){
		char c;T num;
		while(!isdigit(c=gc()));num=c^48;
		while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
		return num;
	}
	inline int gi(){return get<int>();}
}
using namespace IO;

using std::cerr;
using std::cout;

cs int N=1.5e5+7;

int p;
struct node{int cnt,a[5],b[5];}t[N<<2],tp;
int tag[N<<2];

inline node operator+(cs node &x,cs node &y){
	node z=x;
	for(int re i=0;i<y.cnt;++i){
		bool flag=0;
		for(int re j=0;j<z.cnt;++j)
		if(z.a[j]==y.a[i]){z.b[j]+=y.b[i];flag=true;break;}
		if(flag)continue;
		if(z.cnt<p){
			z.a[z.cnt]=y.a[i];
			z.b[z.cnt++]=y.b[i];
			continue;
		}int k=0;
		for(int re j=1;j<z.cnt;++j)if(z.b[j]<z.b[k])k=j;
		if(y.b[i]<z.b[k])for(int re j=0;j<z.cnt;++j)z.b[j]-=y.b[i];
		else {
			int tp=z.b[k];
			z.a[k]=y.a[i];z.b[k]=y.b[i];
			for(int re j=0;j<z.cnt;++j)z.b[j]-=tp;
		}
	}
	return z;
}

#define lc u<<1
#define rc u<<1|1
inline void pushdown(int u,int len){
	int &x=tag[u];
	if(x){
		tag[lc]=tag[rc]=t[lc].a[0]=t[rc].a[0]=x;
		t[lc].cnt=t[rc].cnt=1;x=0;
		t[lc].b[0]=len+1>>1,t[rc].b[0]=len>>1;
	}
}

int a[N];
inline void build(int u,int l,int r){
	if(l==r){t[u].cnt=1,t[u].a[0]=a[l],t[u].b[0]=1;return ;}
	int mid=l+r>>1;
	build(lc,l,mid);build(rc,mid+1,r);
	t[u]=t[lc]+t[rc];
}
inline void modify(int u,int l,int r,int ql,int qr,int v){
	if(ql<=l&&r<=qr){
		t[u].cnt=1,tag[u]=t[u].a[0]=v,t[u].b[0]=r-l+1;
		return ;
	}pushdown(u,r-l+1);
	int mid=l+r>>1;
	if(ql<=mid)modify(lc,l,mid,ql,qr,v);
	if(mid<qr)modify(rc,mid+1,r,ql,qr,v);
	t[u]=t[lc]+t[rc];
}
inline void query(int u,int l,int r,int ql,int qr){
	if(ql<=l&&r<=qr){tp=tp+t[u];return ;}
	int mid=l+r>>1;pushdown(u,r-l+1);
	if(ql<=mid)query(lc,l,mid,ql,qr);
	if(mid<qr)query(rc,mid+1,r,ql,qr);
}
int n,m;
signed main(){
#ifdef zxyoi
	freopen("ad.in","r",stdin);
#endif
	n=gi(),m=gi(),p=100/gi();
	for(int re i=1;i<=n;++i)a[i]=gi();
	build(1,1,n);
	while(m--){
		switch(gi()){
			case 1:{
				int l=gi(),r=gi(),v=gi();
				modify(1,1,n,l,r,v);
				break;
			}
			case 2:{
				tp.cnt=0;
				int l=gi(),r=gi();
				query(1,1,n,l,r);cout<<tp.cnt;
				for(int re i=0;i<tp.cnt;++i)cout<<" "<<tp.a[i];
				cout<<"\n";
				break;
			}
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值