题解 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\n",s);
        while(k--)
            read(x),modify(x,s);
    }
    printf("%d\n",query(1,n));
    return 0;
}
posted @ 2020-09-02 21:46  试试事实上吗  阅读(210)  评论(0编辑  收藏  举报
Live2D