题目传送门: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;
}