P8496 [NOI2022] 众数
分析
假如没有操作 ,怎么维护这些序列呢?由于修改只在末尾进行,于是我们可以仿照建图时的头插法将一个序列的数字插入邻接表中,这样 就是序列 的末尾了。
但是,操作 的合并时,我们需要让 的首个数字的 指针指向 的末尾数字,因此可以再记录一个 表示邻接表的末尾(也就是序列 的首个数字):
void add(int x,int y){
val[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;
if(!nxt[tot])
tail[x]=tot;
}
void del(int x){
head[x]=nxt[head[x]];
if(!head[x])
tail[x]=0;
}
对于操作 你可能会这么写:
//x,y,z分别表示x1,x2,x3
x=read();y=read();z=read();
head[z]=head[y];
tail[z]=tail[x];
nxt[tail[y]]=head[x];
然而交上去只有 分,,原来题目中说的是 为非负整数,后面的删除操作也可能使 变为 ,这个 则可能使邻接表中多出一个数字 ,切断了邻接表,因此必须加一些特判:
//x,y,z分别表示x1,x2,x3
x=read();y=read();z=read();
head[z]=(head[y]?head[y]:head[x]);
tail[z]=(tail[x]?tail[x]:tail[y]);
if(head[x]&&head[y])
nxt[tail[y]]=head[x];
这样对序列的维护就解决了,接下来就是求众数,因为题目中要求众数的出现次数必须大于数的个数的一半,所以就可以用摩尔投票法解决,对于每个序列开一个动态开点权值线段树,维护一个区间的众数和它在摩尔投票中剩余的票数,向上传递信息时,众数为票数较大的那一个,剩余的票数就是多的减去少的。合并 个序列时,只需要将 颗线段树的众数用摩尔投票法合并即可,别忘了最后统计众数的出现的次数是否超过一半。
这样,对于操作 ,直接单点加,对于操作 ,我们用邻接表得到末尾数字并单点减,对于操作 就可以线段树合并,这题就解决了。
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
long long read(){
long long x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;
}
void write(long long x){
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
const int N=1e6+10;
int n,q,l[N],xx[N];
int head[N],nxt[N],val[N],tail[N],tot;
void add(int x,int y){
val[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;
if(!nxt[tot])
tail[x]=tot;
}
void del(int x){
head[x]=nxt[head[x]];
if(!head[x])
tail[x]=0;
}
void cmp(pair<int,int> &x,pair<int,int> y,pair<int,int> z){
if(y.first==z.first){
x.first=y.first;
x.second=y.second+z.second;
}
else if(y.second>z.second){
x.first=y.first;
x.second=y.second-z.second;
}
else{
x.first=z.first;
x.second=z.second-y.second;
}
}
#define pl a[p].tl
#define pr a[p].tr
struct Segment_Tree{
int tot,root[N],cnt,nc[N<<3];
struct Tree{
int tl,tr;
int vsum;
pair<int,int> zs;
}a[N<<3];
Segment_Tree(){
tot=0;
}
int get_new(){
return cnt?nc[cnt--]:++tot;
}
void del(int p){
nc[++cnt]=p;
a[p].tl=a[p].tr=a[p].zs.first=a[p].zs.second=a[p].vsum=0;
}
void pushup(int p){
cmp(a[p].zs,a[pl].zs,a[pr].zs);
a[p].vsum=a[pl].vsum+a[pr].vsum;
}
void add(int p,int x,int v,int L,int R){
if(L==R){
a[p].zs.first=L;
a[p].zs.second+=v;
a[p].vsum+=v;
return;
}
int mid=(L+R)>>1;
if(x<=mid){
if(!pl)
pl=get_new();
add(pl,x,v,L,mid);
}
else{
if(!pr)
pr=get_new();
add(pr,x,v,mid+1,R);
}
pushup(p);
}
int asksum(int p,int l,int r,int L,int R){
if(l<=L&&R<=r)
return a[p].vsum;
int mid=(L+R)>>1;
int ans=0;
if(!pl)
pl=get_new();
if(!pr)
pr=get_new();
if(l<=mid)
ans+=asksum(pl,l,r,L,mid);
if(r>mid)
ans+=asksum(pr,l,r,mid+1,R);
return ans;
}
int merge(int x,int y,int l,int r){
if(!x||!y)
return x+y;
if(l==r){
a[x].zs.first=l;
a[x].zs.second+=a[y].zs.second;
a[x].vsum+=a[y].vsum;
return x;
}
int mid=(l+r)>>1;
a[x].tl=merge(a[x].tl,a[y].tl,l,mid);
a[x].tr=merge(a[x].tr,a[y].tr,mid+1,r);
del(y);
pushup(x);
return x;
}
}tree;
int main(){
n=read();q=read();
for(int i=1;i<=n;i++){
tree.root[i]=tree.get_new();
}
for(int i=1;i<=n;i++){
l[i]=read();
for(int j=1;j<=l[i];j++){
int x=read();
add(i,x);
tree.add(tree.root[i],x,1,1,n+q);
}
}
for(int i=1;i<=q;i++){
ll op,m,x,y,z;
op=read();
if(op==1){
x=read();y=read();
add(x,y);
tree.add(tree.root[x],y,1,1,n+q);
}
else if(op==2){
x=read();
tree.add(tree.root[x],val[head[x]],-1,1,n+q);
del(x);
}
else if(op==3){
m=read();
pair<int,int>u;
u.first=u.second=0;
for(int j=1;j<=m;j++){
xx[j]=read();
cmp(u,u,tree.a[tree.root[xx[j]]].zs);
}
if(!u.first){
puts("-1");
continue;
}
x=0;y=0;
for(int j=1;j<=m;j++){
x+=tree.asksum(tree.root[xx[j]],1,n+q,1,n+q);
y+=tree.asksum(tree.root[xx[j]],u.first,u.first,1,n+q);
}
if(y*2>x){
write(u.first);
puts("");
}
else{
puts("-1");
}
}
else{
//x,y,z分别表示x1,x2,x3
x=read();y=read();z=read();
tree.root[z]=tree.get_new();
tree.merge(tree.root[z],tree.root[x],1,n+q);
tree.merge(tree.root[z],tree.root[y],1,n+q);
head[z]=(head[y]?head[y]:head[x]);
tail[z]=(tail[x]?tail[x]:tail[y]);
if(head[x]&&head[y])
nxt[tail[y]]=head[x];
}
}
return 0;
}

浙公网安备 33010602011771号