给出
n
n
个数,其中有一个数出现过 次 输出这个数。
n<=5∗105
n
<=
5
∗
10
5
空间限制
1MB
1
M
B
时限
0.1s
0.1
s
思考这个数的性质, 这样的数有且只有一个,其他数的总和加起来没有这个数多。
设这个数为p
所以
sump−sumother>0
s
u
m
p
−
s
u
m
o
t
h
e
r
>
0
我们开一个计数器记录当前(伪)最多的数是谁,遇到相同的数,数量
+1
+
1
.否则数量
−1
−
1
.如果到
0
0
了就把这个数替换。
#include<cstdio>
using namespace std;
int main(){
int n,now=-1,tim=0,tmp=0;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&tmp);
if(now!=tmp){
if(tim==0)now=tmp,tim=1;
else tim--;
}
else tim++;
}
printf("%d\n",now);
return 0;
}
总统选举
秋之国共有n个人,分别编号为1,2,…,n,一开始每个人都投了一票,范围1~n,表示支持对应编号的人当总统。共有m次预选,每次选取编号[li,ri]内的选民展开小规模预选,在该区间内获得超过区间大小一半的票的人获胜,如果没有人获胜,则由小C钦定一位候选者获得此次预选的胜利(获胜者可以不在该区间内),每次预选的结果需要公布出来,并且每次会有ki个人决定将票改投向该次预选的获胜者。全部预选结束后,公布最后成为总统的候选人。
每次询问区间内有没有超过一半的数以及数是谁,以及修改一些数。
引用 AbEver A b E v e r 博客中的一段话。
题目不同之处在于支持修改,所以需要线段数维护,为什么线段树可以呢?
因为线段数能维护的东西有两点性质:
①维护的信息满足区间加法。就是说一个区间分为左右两个区间,这两个区间的信息是可加(即合并)的。例如区间和等于左区间和与右区间和的和,区间最值等于左区间最值与右区间最值的最值……
②能直接维护的信息一定是个封闭的域,即可以自己维护自己。这貌似是一句废话,我们明确知道当前区间一定能够维护想维护信息的准确结果。例如我们可以维护最值与和,因为这与其他区间无关,我们也可以维护区间内1的个数,也可以维护从左开始的最长连续的1的个数,从右边开始也行,但是不能直接维护整个区间的最长连续的1的个数。为什么呢?因为当两个区间合并时,就无法维护跨越两个区间的那部分了,就是说有一部分维护不了了。就这么简单,所以才要开三个数组来维护这个东西。
区间问题线段树的可合并性。我们仍然按照刚刚的方法去求
>1/2
>
1
/
2
的个数的数,然后对于每个区间进行合并。
这样求出的众数不一定是正确的,我们对每个权值开一颗线段树维护有哪些人选了他们(部分分的启示)
然后判断这个数在区间的出现次数。
细节的地方比如两个空treap不合并,插入删除的时候对根进行改变(&)之类的要注意一下。然后就一遍A啦。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<set>
#include<map>
#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;
const int MAXN=5e5+5;
typedef pair<int,int>par;
#define mp make_pair
int n,m,a[MAXN];
struct xds{
#define lson (o<<1)
#define rson (o<<1|1)
par maxv[MAXN<<2];
par pushup(par l,par r){
par vo;
if(l.second!=r.second){
if(l.first>=r.first){
vo.first=l.first-r.first;
vo.second=l.second;
}
else {
vo.first=r.first-l.first;
vo.second=r.second;
}
}
else vo=mp(l.first+r.first,l.second);
return vo;
}
void build(int o,int l,int r){
if(l==r){maxv[o].first=1;maxv[o].second=a[l];return;}
int mid=l+r>>1;
build(lson,l,mid);build(rson,mid+1,r);
maxv[o]=pushup(maxv[lson],maxv[rson]);
}
void change(int o,int l,int r,int pos,int val){
if(l==r){maxv[o].first=1;maxv[o].second=val;return;}
int mid=l+r>>1;
if(pos<=mid)change(lson,l,mid,pos,val);
else change(rson,mid+1,r,pos,val);
maxv[o]=pushup(maxv[lson],maxv[rson]);
}
inline par query(int o,int l,int r,int ql,int qr){
if(ql<=l&&qr>=r)return maxv[o];
int mid=l+r>>1;par ls=mp(0,0),rs=mp(0,0);
if(ql<=mid)ls=query(lson,l,mid,ql,qr);
if(qr>mid)rs=query(rson,mid+1,r,ql,qr);
return pushup(ls,rs);
}
#undef lson
#undef rson
}ST;
struct treap{
int size[MAXN*3],lson[MAXN*3],rson[MAXN*3],prio[MAXN*3],val[MAXN*3],rt[MAXN],cnt;
int sta[MAXN],top,pre;
inline void pushup(int p){
size[p]=size[lson[p]]+size[rson[p]]+1;
}
par split(int p,int x){
if(!x)return mp(0,p);
int l=lson[p],r=rson[p];
if(x<=size[l]){
par tem=split(l,x);
lson[p]=tem.second;pushup(p);return mp(tem.first,p);
}
par tem=split(r,x-size[l]-1);
rson[p]=tem.first;pushup(p);return mp(p,tem.second);
}
int merge(int x,int y){
if(!x){pushup(y);return y;}
if(!y){pushup(x);return x;}
if(prio[x]<prio[y]){
rson[x]=merge(rson[x],y);pushup(x);return x;
}
lson[y]=merge(x,lson[y]);pushup(y);return y;
}
int newnode(int x){
size[++cnt]=1;lson[cnt]=rson[cnt]=0;prio[cnt]=rand();val[cnt]=x;
return cnt;
}
int build(vector<int> A,int n){
sta[1]=top=0;
for(int i=0;i<n;i++){
pre=0;
int dq=newnode(A[i]);
while(top&&prio[sta[top]]>prio[dq]){
pre=sta[top--];pushup(pre);
}
if(top)rson[sta[top]]=dq;
lson[dq]=pre;
sta[++top]=dq;
}
while(top)pushup(sta[top--]);
return sta[1];
}
inline int bquerymin(int RT,int pos){//严格小于pos最大的
int p=RT,ans=0;
while(p){
if(val[p]<pos)ans+=size[lson[p]]+1,p=rson[p];
else p=lson[p];
}
return ans;
}
inline int bquerymax(int RT,int pos){//小等于 pos最大的
int p=RT,ans=0;
while(p){
if(val[p]<=pos)ans+=size[lson[p]]+1,p=rson[p];
else p=lson[p];
}
return ans;
}
inline void del(int &RT,int v){//在RT树中删掉val
// cout<<RT<<"s:"<<val<<endl;
int sz=bquerymin(RT,v);
par t1=split(RT,sz);
// cout<<"ok"<<t1.second<<"wly"<<size[t1.second];
par t2=split(t1.second,1);
// cout<<"pk";
if(t1.first||t2.second)RT=merge(t1.first,t2.second);
else RT=0;
}
inline void insert(int &RT,int v){//在RT树中添加val
int sz=bquerymax(RT,v);
// cout<<sz<<"y"<<endl;
par t1=split(RT,sz);
RT=merge(merge(t1.first,newnode(v)),t1.second);
// debug(RT);
// cout<<val[RT]<<"kkk"<<val[rson[RT]]<<endl;
// puts("qaq");
}
void debug(int p){
if(lson[p])debug(lson[p]);
printf("%d ",val[p]);
if(rson[p])debug(rson[p]);
}
}TRP;
vector<int>xp[MAXN];//那个权值有哪些位置的人
//ai 为i位置的人选了谁
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
xp[a[i]].push_back(i);
}
ST.build(1,1,n);
for(int i=1;i<=n;i++)TRP.rt[i]=TRP.build(xp[i],xp[i].size());
for(int i=1;i<=m;i++){
int li,ri,si,ki;
scanf("%d%d%d%d",&li,&ri,&si,&ki);
int p=ST.query(1,1,n,li,ri).second;
int lsz=TRP.bquerymin(TRP.rt[p],li);
int rsz=TRP.bquerymax(TRP.rt[p],ri);
// cout<<p<<":"<<rsz-lsz<<endl;
// cout<<p<<endl;
if(rsz-lsz<=((ri-li+1)>>1))p=si;
for(int j=1;j<=ki;j++){
int val;
scanf("%d",&val);
if(a[val]==p)continue;
TRP.del(TRP.rt[a[val]],val);
TRP.insert(TRP.rt[p],val);
a[val]=p;
ST.change(1,1,n,val,p);
}
printf("%d\n",p);
}
int p=ST.query(1,1,n,1,n).second;
int lsz=TRP.bquerymin(TRP.rt[p],1);
int rsz=TRP.bquerymax(TRP.rt[p],n);
if(rsz-lsz<=(n>>1))p=-1;
printf("%d\n",p);
return 0;
}
/*
5 4
1 2 3 4 5
1 2 1 1 3
5 5 1 2 2 4
2 4 2 0
3 4 2 1 4
*/