P3765 总统选举

题目链接

一道及其恶心的题

大概题意就是维护动态的区间中大于一半的数

怎么办呢?我们把这个过程拆成两部分

  1. 维护区间众数
  2. 判断众数是不是大于一半

对于第一步,我们可以用线段树来维护
对于第二步,我们可以用平衡树来维护

所以,这道题就是线段树+平衡树

首先线段树维护两个量 v a l val val c n t cnt cnt分别表示当前区间的众数和这个区间的众数的优势(比第二大的多多少)

那么 p u s h u p pushup pushup也不难,就是
d e f i n e : l c = u < < 1 , r c = u < < 1 ∣ 1 define :lc=u<<1,rc=u<<1|1 define:lc=u<<1,rc=u<<11
v a l [ u ] = v a l [ l c ] , c n t [ u ] = c n t [ l c ] + c n t [ r c ] ( v a l [ l c ] = v a l [ r c ] ) val[u]=val[lc],cnt[u]=cnt[lc]+cnt[rc](val[lc]=val[rc]) val[u]=val[lc],cnt[u]=cnt[lc]+cnt[rc](val[lc]=val[rc])
e l s e : v a l [ u ] = ( c n t [ l c ] > c n t [ r c ] ? v a l [ l c ] : v a l [ r c ] ) , c n t [ u ] = a b s ( c n t [ l c ] − c n t [ r c ] ) else:val[u]=(cnt[lc]>cnt[rc]?val[lc]:val[rc]),cnt[u]=abs(cnt[lc]-cnt[rc]) else:val[u]=(cnt[lc]>cnt[rc]?val[lc]:val[rc]),cnt[u]=abs(cnt[lc]cnt[rc])
统计的时候就瞎区间查询就可以

接下来我们给每个人写一个平衡树,表示支持他的人的 i d id id
我们把可能是答案的值从线段树里查询出来之后就往这个人的平衡树里查询,看是不是大于区间的一半

这题恶心在要写两颗树,而且都不太好写(特别是这题的线段树我调了两天)

# include <cstdio>
# include <algorithm>
# include <cstring>
# include <cmath>
# include <climits>
# include <iostream>
# include <string>
# include <queue>
# include <stack>
# include <vector>
# include <set>
# include <map>
# include <cstdlib>
# include <ctime>
using namespace std;

# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)

typedef long long ll;
const int N=5e5+5;
const int inf=0x7fffffff;
const double eps=1e-7;
template <typename T> void read(T &x){
	x=0;int f=1;
	char c=getchar();
	for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
	for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
	x*=f;
}

int n,m,tot;
int stand[N];

struct segment_tree_node{
	int l,r,val,cnt;	
}seg[N<<2];

int fa[N*10],son[N*10][2],siz[N*10],key[N*10];

struct segment_tree{
	# define lc (u<<1)
	# define rc (u<<1|1)
	void pushup(int u){
		if(seg[lc].val==seg[rc].val)seg[u].val=seg[lc].val,seg[u].cnt=seg[lc].cnt+seg[rc].cnt;
		else if(seg[lc].cnt>=seg[rc].cnt)seg[u].cnt=seg[lc].cnt-seg[rc].cnt,seg[u].val=seg[lc].val;
		else seg[u].cnt=seg[rc].cnt-seg[lc].cnt,seg[u].val=seg[rc].val;
	}
	void build(int u,int l,int r){
		seg[u].l=l,seg[u].r=r;
		if(l==r){seg[u].val=stand[l],seg[u].cnt=1;return;}
		int mid=l+r>>1;
		build(lc,l,mid);
		build(rc,mid+1,r);
		pushup(u);
	}	
	void update(int u,int x,int k){
		if(seg[u].l==seg[u].r){seg[u].val=k;seg[u].cnt=1;return;}
		int mid=seg[u].l+seg[u].r>>1;
		if(x<=mid)update(lc,x,k);
		else update(rc,x,k);
		pushup(u);	
	}
	segment_tree_node query(int u,int l,int r){
		if(seg[u].l==l&&seg[u].r==r)return seg[u];
		int mid=seg[u].l+seg[u].r>>1;
		if(r<=mid)return query(lc,l,r);
		if(l>mid)return query(rc,l,r);
		segment_tree_node a=query(lc,l,mid),b=query(rc,mid+1,r),c;
		if(a.val==b.val)c.val=a.val,c.cnt=a.cnt+b.cnt;
		else if(a.cnt>=b.cnt)c.val=a.val,c.cnt=a.cnt-b.cnt;
		else c.val=b.val,c.cnt=b.cnt-a.cnt;
		return c;
	}
}a;

struct Splay{
	int rt;
	void clear(int x){fa[x]=son[x][0]=son[x][1]=siz[x]=key[x]=0;}
	bool locate(int x){return son[fa[x]][1]==x;}
	void update(int x){siz[x]=siz[son[x][0]]+siz[son[x][1]]+1;}
	int create(int x,int faz){
		tot++;
		fa[tot]=faz,key[tot]=x;
		son[tot][0]=son[tot][1]=0;
		siz[tot]=1;
		return tot;	
	}
	void rotate(int x){
		int faz=fa[x],grand=fa[faz],side=locate(x);
		son[faz][side]=son[x][side^1],fa[son[faz][side]]=faz;
		son[x][side^1]=faz,fa[faz]=x;
		fa[x]=grand;
		if(grand)son[grand][son[grand][1]==faz]=x;
		update(faz),update(x);	
	}
	void splay(int x,int tar){
		if(!tar)rt=x;
		while(fa[x]!=tar){
			if(fa[fa[x]]!=tar)rotate(locate(x)==locate(fa[x])?fa[x]:x);
			rotate(x); 
		}	
	}
	void find(int x){
		int u=rt;if(!u)return;
		while(son[u][x>key[u]]&&key[u]!=x)u=son[u][x>key[u]];
		splay(u,0); 
	}
	int pre(int x){
		int u=rt;
		if(key[u]<x)return u;
		u=son[rt][0];
		while(son[u][1])u=son[u][1];
		return u;
	}
	int rank(int x){
		find(x);
		if(key[rt]!=x)x=key[pre(x)];
		int u=rt,res=0;
		while(1){
			if(x<key[u])u=son[u][0];
			else{
				res+=siz[son[u][0]];
				if(x==key[u]){
					splay(u,0);
					return res;	
				}
				res++;
				u=son[u][1];
			}
		}
	}
	void insert(int x){
		if(!rt){
			rt=create(x,0);
			return;	
		}
		int u=rt,faz=0;
		while(1){
			faz=u,u=son[u][x>key[u]];
			if(!u){
				son[faz][x>key[faz]]=create(x,faz);
				update(faz);
				splay(tot,0);
				return;
			}
		}
	}
	void erase(int x){
		find(x);
		if(!son[rt][0]&&!son[rt][1]){
			clear(rt);
			rt=0;
			return;
		}	
		if(!son[rt][0]){
			int old=rt;
			rt=son[rt][1];
			fa[rt]=0;
			clear(old);
			return;
		}
		if(!son[rt][1]){
			int old=rt;
			rt=son[rt][0];
			fa[rt]=0;
			clear(old);
			return;	
		}
		int old=rt,lft=pre(key[rt]);
		splay(lft,0);
		son[rt][1]=son[old][1];
		fa[son[old][1]]=rt;
		clear(old);
		update(rt); 
	}
}b[N];

int main()
{
	//freopen("p3765.in","r",stdin);
	read(n),read(m);
	Rep(i,1,n)read(stand[i]),b[stand[i]].insert(i);
	Rep(i,1,n)b[i].insert(-1e9),b[i].insert(1e9);
	a.build(1,1,n);
	Rep(i,1,m){
		int l,r,s,q;
		read(l),read(r),read(s),read(q);
		int x=a.query(1,l,r).val;
		int sum=b[x].rank(r)-b[x].rank(l-1);
		if(sum>(r-l+1)/2)s=x;
		while(q--){
			read(x);
			a.update(1,x,s);
			b[stand[x]].erase(x);
			stand[x]=s;
			b[stand[x]].insert(x);	
		}
		printf("%d\n",s);
	}
	int x=a.query(1,1,n).val;
	int sum=b[x].rank(n);
	printf("%d\n",sum>(n/2)?x:-1);
	return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值