[NOI2022] 众数 题解

看到绝对众数的出现,摩尔投票法直接秒了,考虑分为若干个序列,要支持合并操作,那么容易想到线段树,要删除尾部,容易想到链表,因为\(\sum M \le 10^5\),所以在查询的时候可以暴力枚举序列,进行摩尔投票,然后判断剩余的数是不是绝对众数,复杂度\(O(n\log_2{n})\)

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=1e6+10;
int n,m,rt[maxn],op,x,y,z,ans,idd,ge[maxn],jie,nxt[maxn],pre[maxn],fir,sec;
int t[maxn],qi[maxn],news,luo[maxn],val[maxn],lst,rts,now,tp,st[maxn];
struct edge{
	int ls;
	int rs;
	int fir;
	int sec;
	int sum;
}tree[maxn<<4];
inline void push_up(int id){
	if(tree[tree[id].ls].sec>tree[tree[id].rs].sec){
		tree[id].fir=tree[tree[id].ls].fir;
		tree[id].sec=tree[tree[id].ls].sec-tree[tree[id].rs].sec;
	}
	else if(tree[tree[id].ls].sec==tree[tree[id].rs].sec){
		tree[id].fir=tree[id].sec=0;
	}
	else{
		tree[id].fir=tree[tree[id].rs].fir;
		tree[id].sec=tree[tree[id].rs].sec-tree[tree[id].ls].sec;
	}
	return;
}
inline void add(int &id,int l,int r,int q,int w){
	if(!id){
		idd++;
		id=idd;
	}
	if(l==r){
		tree[id].sum+=w;
		tree[id].fir=l;
		tree[id].sec=tree[id].sum;
		return;
	}
	int mid=(l+r)/2;
	if(q<=mid){
		add(tree[id].ls,l,mid,q,w);
	}
	else{
		add(tree[id].rs,mid+1,r,q,w);
	}
	push_up(id);
	return;
}
inline int merges(int q,int w){
	if(!q||!w){
		return q+w;
	}
	if(!tree[q].ls&&!tree[q].rs){
		tree[q].sum+=tree[w].sum;
		tree[q].sec+=tree[w].sec;
		return q;
	}
	tree[q].ls=merges(tree[q].ls,tree[w].ls);
	tree[q].rs=merges(tree[q].rs,tree[w].rs);
	push_up(q);
	return q;
}
inline int query(int id,int l,int r,int q){
	if(l==r){
		return tree[id].sum;
	}
	int mid=(l+r)/2;
	if(q<=mid){
		return query(tree[id].ls,l,mid,q);
	}
	else{
		return query(tree[id].rs,mid+1,r,q);
	}
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n>>m;
	jie=n+m;
	for(int i=1;i<=n;i++){
		cin>>ge[i];
		for(int j=1;j<=ge[i];j++){
			cin>>x;
			news++;
			val[news]=x;
			if(!qi[i]){
				qi[i]=news;
			}
			else{
				pre[news]=lst;
				nxt[lst]=news;
			}
			lst=news;
			luo[i]=news;
			add(rt[i],1,jie,x,1);
		}
	}
	while(m--){
		cin>>op;
		if(op==1){
			cin>>x>>y;
			news++;
			val[news]=y;
			if(!qi[x]){
				qi[x]=news;
			}
			else{
				pre[news]=luo[x];
				nxt[luo[x]]=news;
			}
			luo[x]=news;
			add(rt[x],1,jie,y,1);
			ge[x]++;
		}
		if(op==2){
			cin>>x;
			add(rt[x],1,jie,val[luo[x]],-1);
			luo[x]=pre[luo[x]];
			ge[x]--;
			if(!luo[x]){
				qi[x]=0;
			}
		}
		if(op==3){
			cin>>x;
			tp=0;
			for(int i=1;i<=x;i++){
				tp++;
				cin>>st[tp];
			}
			y=0,z=0,now=idd,rts=0,fir=0,sec=0;
			for(int i=1;i<=x;i++){
				y+=ge[st[i]];
			}
			for(int i=1;i<=x;i++){
				if(tree[rt[st[i]]].fir==fir){
					sec+=tree[rt[st[i]]].sec;
				}
				else if(tree[rt[st[i]]].sec==sec){
					fir=0;
					sec=0;
				}
				else if(tree[rt[st[i]]].sec>sec){
					fir=tree[rt[st[i]]].fir;
					sec=tree[rt[st[i]]].sec-sec;
				}
				else{
					sec-=tree[rt[st[i]]].sec;
				}
			}
			for(int i=1;i<=x;i++){
				z+=query(rt[st[i]],1,jie,fir);
			}
			if(z>y/2){
				cout<<fir<<'\n';
			}
			else{
				cout<<-1<<'\n';
			}
		}
		if(op==4){
			cin>>x>>y>>z;
			rt[z]=merges(rt[x],rt[y]);
			ge[z]=ge[x]+ge[y];
			if(ge[x]&&ge[y]){
				qi[z]=qi[x];
				nxt[luo[x]]=qi[y];
				pre[qi[y]]=luo[x];
				luo[z]=luo[y];
			}
			else if(ge[x]){
				qi[z]=qi[x];
				luo[z]=luo[x];
			}
			else{
				qi[z]=qi[y];
				luo[z]=luo[y];
			}
		}
	}
	return 0;
}
posted @ 2025-05-14 10:04  特别之处  阅读(32)  评论(0)    收藏  举报