洛谷P3765:总统选举 (线段树+treap)

题目传送门:https://www.luogu.org/problem/show?pid=3765

题目分析:线段树好题!线段树好题!线段树好题!(重要的事情说三遍)

在你做这一道题之前,你需要知道一道弱化版的题目的解法:http://www.lydsy.com/JudgeOnline/problem.php?id=2456

少女思考中……

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

我们记录一个val,cnt,表示当前的答案,以及答案出现的次数。每遇到一个新数,如果它和val相等,令cnt++,否则如果cnt>0令cnt--,如果cnt已经为0,就让val=当前数,cnt=1。这样因为ans出现了超过一半次,所以它肯定会留到最后,所以最后的val就是答案。

我在做这P3765之前已经做过上面这题,然而我月赛的时候还是没想出来。我见到sigmaK<=10^6我还以为要支持O(1)修改,于是没往数据结构方面想。然而这题时限五秒,10^6*log(n)无压力……

好吧言归正传,我们发现上面的val,cnt是可以进行信息加法的。我们要求一段区间的val,cnt,我们可以分别先左右两部分的val,cnt。

如果两部分的val相等,就把它们的cnt加起来。如果不等,就取它们cnt较大的那个val,并令整段区间的cnt=两部分cnt差的绝对值(简单来说就是上面那题的做法)。这样我们就可以跑线段树了。

我们查询一个区间的时候,查询出来的val只是可能的答案,至于val是否真的出现超过一半次,我们还要用一棵treap检验。

CODE:

#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;

const int maxn=500100;

struct Tnode
{
	int val,fix,Size;
	Tnode *lson,*rson;
	int Lsize() { return lson? lson->Size:0; }
	void Get_size() { Size=Lsize()+(rson? rson->Size:0)+1; }
} treap[maxn*3];
Tnode *Root[maxn];
int cur=-1;

struct data
{
	int num,cnt;
} tree[maxn<<2];
data zero;

int a[maxn];
int n,m;
int l,r,s,k;

Tnode *New_node(int v)
{
	cur++;
	treap[cur].val=v;
	treap[cur].fix=rand();
	treap[cur].Size=1;
	treap[cur].lson=treap[cur].rson=NULL;
	return treap+cur;
}

void Right_turn(Tnode *&P)
{
	Tnode *W=P->lson;
	P->lson=W->rson;
	W->rson=P;
	P=W;
	P->rson->Get_size();
	P->Get_size();
}

void Left_turn(Tnode *&P)
{
	Tnode *W=P->rson;
	P->rson=W->lson;
	W->lson=P;
	P=W;
	P->lson->Get_size();
	P->Get_size();
}

void Insert(Tnode *&P,int v)
{
	if (!P) P=New_node(v);
	else
		if ( vval )
		{
			Insert(P->lson,v);
			if ( P->lson->fix < P->fix ) Right_turn(P);
			else P->Get_size();
		}
		else
		{
			Insert(P->rson,v);
			if ( P->rson->fix < P->fix ) Left_turn(P);
			else P->Get_size();
		}
}

data Get(data x,data y)
{
	data z;
	if (x.num==y.num) z.num=x.num,z.cnt=x.cnt+y.cnt;
	else
		if (x.cnt>y.cnt) z=x,z.cnt-=y.cnt;
		else z=y,z.cnt-=x.cnt;
	return z;
}

void Build(int root,int L,int R)
{
	if (L==R)
	{
		tree[root].num=a[L];
		tree[root].cnt=1;
		return;
	}
	
	int Left=root<<1;
	int Right=Left|1;
	int mid=(L+R)>>1;
	
	Build(Left,L,mid);
	Build(Right,mid+1,R);
	tree[root]=Get(tree[Left],tree[Right]);
}

data Query(int root,int L,int R,int x,int y)
{
	if ( y>1;
	
	data vl=Query(Left,L,mid,x,y);
	data vr=Query(Right,mid+1,R,x,y);
	return Get(vl,vr);
}

int Ask(Tnode *P,int v)
{
	if (!P) return 0;
	if ( vval ) return Ask(P->lson,v);
	int ls=P->Lsize()+1;
	return ls+Ask(P->rson,v);
}

void Update(int root,int L,int R,int x,int v)
{
	if ( x>1;
	
	Update(Left,L,mid,x,v);
	Update(Right,mid+1,R,x,v);
	tree[root]=Get(tree[Left],tree[Right]);
}

void Delete(Tnode *&P,int v)
{
	if ( v==P->val )
		if (P->lson)
			if (P->rson)
				if ( P->lson->fix < P->rson->fix )
					Right_turn(P),Delete(P->rson,v),P->Get_size();
				else Left_turn(P),Delete(P->lson,v),P->Get_size();
			else P=P->lson;
		else P=P->rson;
	else
		if ( vval ) Delete(P->lson,v),P->Get_size();
		else Delete(P->rson,v),P->Get_size();
}

int main()
{
	freopen("c.in","r",stdin);
	freopen("c.out","w",stdout);
	
	srand( time(0) ),rand(),rand();
	scanf("%d%d",&n,&m);
	for (int i=1; i<=n; i++) Root[i]=NULL;
	for (int i=1; i<=n; i++) scanf("%d",&a[i]),Insert(Root[ a[i] ],i);
	Build(1,1,n);
	
	zero.num=zero.cnt=0;
	for (int i=1; i<=m; i++)
	{
		scanf("%d%d%d%d",&l,&r,&s,&k);
		data x=Query(1,1,n,l,r);
		int v=Ask(Root[ x.num ],r)-Ask(Root[ x.num ],l-1);
		if (2*v<=r-l+1) x.num=s;
		printf("%d\n",x.num);
		for (int j=1; j<=k; j++)
			scanf("%d",&s),Update(1,1,n,s,x.num),Delete(Root[ a[s] ],s),
			Insert(Root[ x.num ],s),a[s]=x.num;
	}
	data x=tree[1];
	int v=Ask(Root[ x.num ],n);
	if (2*v>n) printf("%d\n",x.num);
	else printf("-1\n");
	
	return 0;
}

你可能感兴趣的:(普通nlog(n)数据结构,treap)