Miaomiao

Home

Rainy Season, having the hard way with you


Luogu_MayR1 B 总统选举

Description

  秋之国共有n个人,分别编号为1,2,…,n,一开始每个人都投了一票,范围1~n,表示支持对应编号的人当总统。共有m次预选,每次选取编号[$l_i$,$r_i$]内的选民展开小规模预选,在该区间内获得超过区间大小一半的票的人获胜,如果没有人获胜,则由小C钦定一位候选者获得此次预选的胜利(获胜者可以不在该区间内),每次预选的结果需要公布出来,并且每次会有$k_i$个人决定将票改投向该次预选的获胜者。全部预选结束后,公布最后成为总统的候选人。

Input

  第一行两个整数n,m,表示秋之国人数和预选次数。

  第二行n个整数,分别表示编号1~n的选民投的票。

  接下来m行,每行先有4个整数,分别表示$l_i,r_i,s_i,k_i,s_i$表示若此次预选无人胜选,视作编号为$s_i$的人获得胜利,接下来$k_i$个整数,分别表示决定改投的选民。

Output

  共m+1行,前m行表示各次预选的结果,最后一行表示最后成为总统的候选人,若最后仍无人胜选,输出-1。

Analysis

  考虑如下操作:

  对于一列数,从头到尾开始扫描,记录num与cnt。 初始num=cnt=0,每次加入一个新的数字时,如果这个数字与num相同,则++cnt。如果不相同,如cnt>0则–cnt,否则num被替换为现在的数字,cnt=1

  那么如果有答案的话,答案一定是最后的num。可以发现这个信息可以被区间维护(相同相加,不同相减区大者)。虽然出来的信息比较奇怪,但是如果在本区间有答案的话,一定是最后的num

  接下来的工作是处理num在某个区间中出现了多少次,比较好的方法是用splay。对于每一个候选者建一棵splay,节点就是投票者(其实是n棵splay共用n个节点了),于是就可以求出某一区间中某人被投票的次数了。至于修改,就是删点和加点了。   

Thoughts

  1.本题思维比较巧妙,某些时候我们只需保证答案的正确性而中间的结果似乎不那么重要(那个处理出现次数大于一半的做法很巧妙)

  2.个人觉得splay的用法很好,多棵splay可以共用节点(维护区间出现次数信息并支持修改)   

Code

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<set>

#define LL long long
#define For(i, a, b) for(int i = (a); i <= (int)(b); ++i)

using namespace std;

#define N (500000+5)
#define Ite set<int>::iterator

char chr;
inline void Read(int &x){
    chr = getchar();
    while(chr < '0' || chr > '9') chr = getchar();
    x = 0;
    while(chr >= '0' && chr <= '9'){
        x = (x<<1)+(x<<3)+(chr^'0'); chr = getchar();
    }
}

inline void Write(int x){
    if(!x) return;
    Write(x/10);
    putchar(x%10+'0');
}

struct node{
    int v, cnt;
    
    node operator +(const node &rhs)const{
        if(v == rhs.v) return (node){v, cnt+rhs.cnt};
        if(cnt > rhs.cnt) return (node){v, cnt-rhs.cnt};
        if(cnt < rhs.cnt) return (node){rhs.v, rhs.cnt-cnt};
        return (node){!v? rhs.v: v, 0};
    }
};

int ql, qr, ch[N][2], fa[N], siz[N], my[N];

#define lc (o<<1)
#define rc (o<<1|1)
#define mid ((L+R)>>1)
//struct SegTree{
    node tr[N<<2];    
    
    inline void Build(int o, int L, int R){
        if(L == R){tr[o] = (node){my[L], 1}; return;}
        
        Build(lc, L, mid); Build(rc, mid+1, R);
        tr[o] = tr[lc]+tr[rc];
    }

    inline void Modify(int o, int L, int R, int pos){
        if(L == R){tr[o] = (node){my[L], 1}; return;}
        
        if(pos <= mid) Modify(lc, L, mid, pos);
        else Modify(rc, mid+1, R, pos);
        tr[o] = tr[lc]+tr[rc];
    }

    inline node Query(int o, int L, int R){
        if(ql <= L && qr >= R) return tr[o];
        
        node ret = (node){0, 0};
        if(ql <= mid) ret = ret+Query(lc, L, mid);
        if(qr > mid) ret = ret+Query(rc, mid+1, R);
        return ret;
    }
//}ST;
#undef lc
#undef rc
#undef mid

Ite it;

#define lc ch[o][0]
#define rc ch[o][1]
struct SPLAY{
    int rt;
    set<int> mem;

    inline void maintain(int o){
        siz[o] = 1;
        if(lc) siz[o] += siz[lc]; if(rc) siz[o] += siz[rc];
    }

    inline void Rotate(int o){
        int f = fa[o], g = fa[f];
        int c = o==ch[f][1];

        if(g) ch[g][ch[g][1]==f] = o;
        fa[o] = g; fa[f] = o; fa[ch[o][c^1]] = f;
        ch[f][c] = ch[o][c^1]; ch[o][c^1] = f;

        maintain(f); maintain(o);
    }
    
    inline void Splay(int x, int aim){
        int f, g;

        while(fa[x] != aim){
            f = fa[x]; g = fa[f];
            if(g != aim) Rotate(f);
            Rotate(x);
        }

        if(!aim) rt = x;
    }

    inline void Insert(int now){
        siz[now] = 1; mem.insert(now);
        if(!rt){rt = now; return;}
        
        int x = rt;
        while(ch[x][now>x]) x = ch[x][now>x];
        ch[x][now>x] = now; fa[now] = x;
        Splay(now, 0);
    }

    inline void Del(int o){
        mem.erase(o);
        if(o == rt && siz[o] == 1){rt = 0; siz[o] = 0; return;}
        
        while(siz[lc] || siz[rc]){
            if((siz[lc] < siz[rc]&&siz[lc]) || !siz[rc]){
                if(o==rt) rt = lc; Rotate(lc);
            }else{
                if(o==rt) rt = rc; Rotate(rc);
            }
        }

        int f = fa[o];
        ch[f][ch[f][1]==o] = 0; fa[o] = 0; siz[o] = 0;
        while(f){maintain(f); f = fa[f];}
    }

    inline int count(int Min, int Max){
        int u = *mem.lower_bound(Min);
        it = mem.upper_bound(Max); if(*it != Max) --it;
        int v = *it;
        
        if(u > v) return 0; if(u == v) return 1;
        Splay(u, 0); Splay(v, u);

        return siz[ch[v][0]]+2;
    }
}spl[N];

#undef lc
#undef rc

int main(){
#ifndef ONLINE_JUDGE
    freopen("test.in", "r", stdin);
    freopen("test.out", "w", stdout);
#endif

    int n, m, s, k;

    Read(n); Read(m);
    For(i, 1, n){
        Read(my[i]); spl[my[i]].Insert(i);
    }

    Build(1, 1, n);
    node now;
    
    int half, pre, np;
    while(m--){
        Read(ql); Read(qr); Read(s); Read(k);
        half = (qr-ql+1)>>1, now = Query(1, 1, n);
        if(spl[now.v].count(ql, qr) > half) pre = now.v;
        else pre = s;

        For(i, 1, k){
            Read(np); if(my[np] == pre) continue;
            
            spl[my[np]].Del(np); spl[my[np]=pre].Insert(np);
            Modify(1, 1, n, np);
        }

        Write(pre); puts("");
    }
    
    half = (n>>1);
    For(i, 1, n)
        if(siz[spl[i].rt]>half){
            Write(i); puts(""); return 0;
        } 
    puts("-1");
    
    return 0;
}