BZOJ 2456 and 洛谷总统选举

给出 n n 个数,其中有一个数出现过>0.5n+1 次 输出这个数。
n<=5105 n <= 5 ∗ 10 5 空间限制 1MB 1 M B 时限 0.1s 0.1 s

思考这个数的性质, 这样的数有且只有一个,其他数的总和加起来没有这个数多。
设这个数为p
所以 sumpsumother>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个人决定将票改投向该次预选的获胜者。全部预选结束后,公布最后成为总统的候选人。

每次询问区间内有没有超过一半的数以及数是谁,以及修改一些数。
n,m<=5105,k<=1065s

引用 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
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值