zoukankan      html  css  js  c++  java
  • 题解 P3765 【总统选举】

    原文链接

    很有意思的一道题。

    Part.1

    一开始拿到这道题一看,题目要求的是区间众数的出现次数,这个显然没法做,据我所知只有静态分块或者回滚莫队可以做不带修版本的,但是他要我们求的比这个要弱许多,我们可以发现一个性质,显然如果一个数出现次数超过一半,我们让它与剩下的数两两抵消,剩下的数必然只有它自己。更进一步,如果区间中一旦有一个满足条件的数,我们任意选不同的两个数抵消,剩下的必然是那个数。

    我们用数据结构实现这个过程。

    考虑一棵线段树,她维护区间中两两抵消还剩哪个数以及还剩多少。她的左右儿子信息合并时,我们看两个儿子剩下的数是否一样,如果一样就相加,如果不一样就取最大,然后互相抵消。

    Part.2

    然后,你以为做完了?

    如果真做完了那么它最多是绿题。

    我们刚才假设了区间绝对满足条件,那么如果区间不满足条件呢?暴力找

    一个显然的做法是对每一个总统建一个(vector),每次找出答案后再(vector)中二分询问区间的左右端点,然后看中间数的个数是否大于(len/2)就可以了。

    然而题目中有修改。暴力修改

    于是实际上,我们要支持一个数据结构,插入一个数,删除一个数,查询某个数的排名(相当与二分)

    这是什么?平衡树板子。

    然后,然后就真的完了。

    总结一下,我们每次在线段树上找出一个数,然后再在平衡树上找出区间中该数的个数检查是否合法就可以了。

    Part.3

    安利一下(LeafyTree),即(WBLT),她的形态与线段树差不多,常数小跑的飞快,一般比(Splay)(FHQTreap)快两到三倍。

    最后一个细节,在找排名的时候,一路走到叶子后一定要看一下这个数是不是比叶子大,如果小要(return;0),因为这个数可能比平衡树中的所有数都小。

    Code

    struct Node
    {
        int siz,val;
        Node *lc,*rc;
        Node(int siz,int val,Node *lc,Node *rc) : siz(siz),val(val),lc(lc),rc(rc) {}
        Node() {}
    }*null,*stk[maxn*3],utk[maxn*3];
    int utot,a[maxn],n;
    
    struct Leafy_Tree
    {
        Node *rt[maxn];
        #define newnode(a,b,c,d) (&(*stk[utot++]=Node(a,b,c,d)))
        #define merge(a,b) newnode(a->siz+b->siz,b->val,a,b)
        inline void init()
        {
            for(int i=1;i<=n;++i)
                rt[i]=newnode(1,0x3f3f3f3f,null,null);
        }
        inline void rotate(Node *u)
        {
            if(u->lc->siz > u->rc->siz*ratio)
                u->rc=merge(u->lc->rc,u->rc),stk[--utot]=u->lc,u->lc=u->lc->lc;
            else if(u->rc->siz > u->lc->siz*ratio)
                u->lc=merge(u->lc,u->rc->lc),stk[--utot]=u->rc,u->rc=u->rc->rc;
        }
        inline void pushup(Node *u)
        {
            if(!u->lc->siz) return;
            u->siz=u->lc->siz+u->rc->siz;
            u->val=u->rc->val;
        }
        inline void insert(Node *u,int val)
        {
            if(u->siz==1)
            {
                u->lc=newnode(1,min(u->val,val),null,null);
                u->rc=newnode(1,max(u->val,val),null,null);
            }
            else insert(val > u->lc->val?u->rc:u->lc,val);
            pushup(u);rotate(u);
        }
        inline void erase(Node *u,int val)
        {
            if(u->lc->siz==1&&u->lc->val==val)
                stk[--utot]=u->lc,stk[--utot]=u->rc,*u=*u->rc;
            else if(u->rc->siz==1&&u->rc->val==val)
                stk[--utot]=u->lc,stk[--utot]=u->rc,*u=*u->lc;
            else erase(val > u->lc->val?u->rc:u->lc,val);
            pushup(u);rotate(u);
        }
        inline int rnk(Node *u,int val)
        {
            if(u->siz==1) return val>=u->val;
            return val > u->lc->val ? rnk(u->rc,val)+u->lc->siz : rnk(u->lc,val);
        }
    }leafy;
    
    struct Segment_Tree
    {
        int mx[maxn],cnt[maxn];
        inline void pushup(int u)
        {
            if(mx[u<<1]==mx[u<<1|1]) mx[u]=mx[u<<1],cnt[u]=cnt[u<<1]+cnt[u<<1|1];
            else if(cnt[u<<1]>cnt[u<<1|1]) mx[u]=mx[u<<1],cnt[u]=cnt[u<<1]-cnt[u<<1|1];
            else mx[u]=mx[u<<1|1],cnt[u]=cnt[u<<1|1]-cnt[u<<1];
        }
        inline void build(int u,int l,int r)
        {
            if(l==r) {mx[u]=a[l],cnt[u]=1;return;}
            int mid=(l+r)>>1;
            build(u<<1,l,mid);build(u<<1|1,mid+1,r);
            pushup(u);
        }
        inline void modify(int u,int l,int r,int x,int val)
        {
            if(l==r) {mx[u]=val;return;}
            int mid=(l+r)>>1;
            if(x<=mid) modify(u<<1,l,mid,x,val);
            else modify(u<<1|1,mid+1,r,x,val);
            pushup(u);
        }
        inline pii query(int u,int l,int r,int x,int y)
        {
            if(x<=l&&r<=y) return make_pair(mx[u],cnt[u]);
            int mid=(l+r)>>1;
            if(y<=mid) return query(u<<1,l,mid,x,y);
            else if(x>mid) return query(u<<1|1,mid+1,r,x,y);
            else
            {
                pii a=query(u<<1,l,mid,x,y),b=query(u<<1|1,mid+1,r,x,y),c;
                if(a.first==b.first) c.first=a.first,c.second=a.second+b.second;
                else if(a.second>b.second) c.first=a.first,c.second=a.second-b.second;
                else c.first=b.first,c.second=b.second-a.second;
                return c;
            }
        }
    }seg;
    
    inline void modify(int x,int val)
    {
        leafy.erase(leafy.rt[a[x]],x);
        leafy.insert(leafy.rt[val],x);
        seg.modify(1,1,n,x,val);
        a[x]=val;
    }
    
    inline int query(int x,int y)
    {
        int ans=seg.query(1,1,n,x,y).first;
        if(((y-x+1)>>1)<leafy.rnk(leafy.rt[ans],y)-leafy.rnk(leafy.rt[ans],x-1)) return ans;
        else return -1;
    }
    
    template<typename T>
    inline void read(T &x)
    {
        char c;int f=1;
        while(!isdigit(c=getchar())) (c=='-')&&(f=-1);
        x=c^48;
        while(isdigit(c=getchar())) x=x*10+(c^48);
        x*=f;
    }
    
    int main()
    {
        int l,r,s,k,m,x;
        for(int i=0;i<maxn*3;++i)
            stk[i]=&utk[i];
        null=new Node(0,0,0,0);
        read(n);read(m);
        for(int i=1;i<=n;++i)
            read(a[i]);
        leafy.init();
        seg.build(1,1,n);
        for(int i=1;i<=n;++i)
            leafy.insert(leafy.rt[a[i]],i);
        while(m--)
        {
            read(l);read(r);read(s);read(k);
            x=query(l,r);
            if(x!=-1) s=x;
            printf("%d
    ",s);
            while(k--)
                read(x),modify(x,s);
        }
        printf("%d
    ",query(1,n));
        return 0;
    }
    
  • 相关阅读:
    php PDO操作类
    PDO笔记
    修改表中的enum字段
    php四种基础算法:冒泡,选择,插入和快速排序法
    MySQL中UNION和UNION ALL的使用
    02-HTML5新的input属性
    01-HTML5的介绍
    03-body标签中相关标签
    02-body标签中相关标签
    01-html介绍和head标签
  • 原文地址:https://www.cnblogs.com/gxm123/p/13604660.html
Copyright © 2011-2022 走看看