NOI2022 众数

经典题目,对于绝对众数只需要考虑这一个序列的中位数在序列中出现次数是否大于一半即可。

这道题用线段树合并维护一下就做完了。

点击查看代码
#include<bits/stdc++.h>
#define fir first
#define sec second
#define int long long
#define mkp(a,b) make_pair(a,b)
using namespace std;
typedef pair<int,int> pir; 
inline int read(){
	int x=0,f=1; char c=getchar();
	while(!isdigit(c)){if(c=='-') f=-1; c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48); c=getchar();}
	return x*f;
}
const int mod=998244353,inf=1e18,N=1e6+5;
int n,q,lim;
int siz[N];
int nxt[N],pre[N],val[N],rt[N],lst[N],fst[N],cnt;

int m;
int qu[N],p[N];
struct tree{
	int cnt;
	int sum[N*20],ls[N*20],rs[N*20];
	inline void push_up(int p){sum[p]=sum[ls[p]]+sum[rs[p]];}
	inline void add(int &p,int l,int r,int num,int k){
		if(!p) p=++cnt;
		if(l==r){sum[p]+=k; return ;}
		int mid=(l+r)>>1;
		if(num<=mid) add(ls[p],l,mid,num,k);
		if(num>mid)  add(rs[p],mid+1,r,num,k);
		push_up(p);
	} 
	inline int merge(int p,int q,int l,int r){
		if(!p||!q) return p^q;
		if(l==r){sum[p]+=sum[q]; return p;}
		int mid=(l+r)>>1;
		ls[p]=merge(ls[p],ls[q],l,mid);
		rs[p]=merge(rs[p],rs[q],mid+1,r);
		push_up(p);
		return p; 
	}
	inline int ask(int p,int l,int r,int num){
		if(l==r) return sum[p];
		int mid=(l+r)>>1;
		if(num<=mid) return ask(ls[p],l,mid,num);
		return ask(rs[p],mid+1,r,num); 
	}
	inline int find(int p[],int l,int r,int S){
		if(l==r) return l;
		int mid=(l+r)>>1;
		int le=0;
		for(int i=1;i<=m;i++) le+=sum[ls[p[i]]];
		if(S>le){
			for(int i=1;i<=m;i++) p[i]=rs[p[i]];
			return find(p,mid+1,r,S-le);
		}
		for(int i=1;i<=m;i++) p[i]=ls[p[i]];
		return find(p,l,mid,S);
	}
}T;
inline void add(int x,int y){
	cnt++;
	siz[x]++;
	val[cnt]=y;
	int ed=lst[x];
	if(ed){
		nxt[ed]=cnt;
		pre[cnt]=ed;	
	}
	lst[x]=cnt;
	if(siz[x]==1) fst[x]=cnt;
	T.add(rt[x],1,lim,y,1);
}
inline void del(int x){
	siz[x]--;
	if(!siz[x]) fst[x]=0;
	int ed=lst[x],y=val[ed];
//	cout<<"del:"<<x<<' '<<ed<<' '<<y<<'\n';
	lst[x]=pre[ed];
	nxt[pre[ed]]=0;
	nxt[ed]=pre[ed]=0;
	T.add(rt[x],1,lim,y,-1);
}
inline void ask(){
	m=read();
	int sum=0;
	for(int i=1;i<=m;i++){
		int x=read();
		qu[i]=p[i]=rt[x],sum+=siz[x];
	}
	int it=T.find(p,1,lim,sum/2+1),C=0;
	for(int i=1;i<=m;i++) C+=T.ask(qu[i],1,lim,it);
//	cout<<it<<' '<<C<<' '<<sum/2<<'\n';
	if(C<=sum/2) puts("-1");
	else cout<<it<<'\n';
}
inline void merge(int x,int y,int z){
	rt[z]=T.merge(rt[x],rt[y],1,lim);
	siz[z]=siz[x]+siz[y];
	int ed=lst[x],fi=fst[y];
	nxt[ed]=fi,pre[fi]=ed;
	if(!ed) nxt[ed]=0;
	if(!fi) pre[fi]=0;
	fst[z]=(siz[x]?fst[x]:fst[y]),lst[z]=(siz[y]?lst[y]:lst[x]);
	fst[x]=fst[y]=lst[x]=lst[y]=0;
}
signed main(){
//	freopen("major.in","r",stdin);
//	freopen("major.out","w",stdout);
	n=read(),q=read(); lim=n+q;
	for(int i=1;i<=n;i++){
		siz[i]=read();
		for(int j=1;j<=siz[i];j++){
			int x=read();
			val[++cnt]=x;
			T.add(rt[i],1,lim,x,1);
			nxt[cnt]=cnt+1,pre[cnt]=cnt-1;
			if(j==1) pre[cnt]=0,fst[i]=cnt;
			if(j==siz[i]) nxt[cnt]=0,lst[i]=cnt;
		}
//		cout<<cnt<<'\n';
	}
	while(q--){
		int opt=read();
		if(opt==1){
			int x=read(),y=read();
			add(x,y);
		}
		if(opt==2){
			int x=read();
			del(x);
		}
		if(opt==3) ask();
		if(opt==4){
			int x=read(),y=read(),z=read();
			merge(x,y,z);
		}
	}
}
posted @ 2024-08-22 16:33  ~Cyan~  阅读(1)  评论(0编辑  收藏  举报