splay + 线段树 ---- P3765总统选举 [带修改的动态区间众数 摩尔投票+n棵splay]

题目链接


题目大意:

在这里插入图片描述


解题思路:

1.摩尔投票法:

  1. 题意是找n个数内出现次数大于n/2的数 保证存在这个数用的方法叫做摩尔投票法

  2. 首先我们注意到这样一个现象: 在任何数组中,出现次数大于该数组长度一半的值只能有一个。

  3. 摩尔投票法的基本思想很简单,在每一轮投票过程中,从数组中找出一对不同的元素,将其从数组中删除。

  4. 这样不断的删除直到无法再进行投票,如果数组为空,则没有任何元素出现的次数超过该数组长度的一半。如果只存在一种元素,那么这个元素则可能为目标元素。

有了这个前置技能以后 这道题的第一个思路应该很明显了:用线段树维护一个区间的cnt和众数

但是用线段树维护 必须保证维护的东西满足区间可加性

显然摩尔投票法是有区间可加性的

具体来说 如果两个儿子的众数相同 这个节点的众数就等于儿子的众数 cnt就等于两个儿子的cnt相加

如果不同 这个节点的众数就等于cnt较大的那个儿子的众数 cnt就等于大的减去小的

写成代码也很简单

    void pushup(int rt) {
        if(tr[rt<<1] == tr[rt<<1|1]) {
            tr[rt] = tr[rt<<1];
            cnt[rt] = cnt[rt<<1] + cnt[rt<<1|1];
        } else if(cnt[rt<<1] >= cnt[rt<<1|1]) {
            tr[rt] = tr[rt<<1];
            cnt[rt] = cnt[rt<<1] - cnt[rt<<1|1];
        } else {
            tr[rt] = tr[rt<<1|1];
            cnt[rt] = cnt[rt<<1|1] - cnt[rt<<1];
        }
    }

2.splay验证

题目是不保证一定存在这个数。那就是意味着我们找到的这个数不一定是对的

那么我们要去 c h e c k check check这个数,怎么 c h e c k check check呢?

我们对于每个人建立一个splay,里面插入支持人的编号,我们说这个人在询问的 [ l , r ] [l,r] [l,r]里面是众数,因为就是每个数字不一样,那么我们只要对这个 s p l a y splay splay里面查询 r a n k rank rank,就是你查询比 r r r小有多少人,比 l l l小有多少人,做差就好了


AC code

这里splay很离谱,查询rank里面有大量的不存在的数,我们对于查不到的数,我们要把这个数的前驱splay到根节点,才能保证复杂度
封装起来每个splay 都有一个root,旋根的时候要记得跟新root

#include <bits/stdc++.h>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x7fffffff
#define LLF 0x3f3f3f3f3f3f3f3f
#define f first
#define s second
#define ls(x) T[x].ch[0]
#define rs(x) T[x].ch[1]
#define fa(x) T[x].fa
#define endl '\n'
using namespace std;
const int N = 5e6 + 10, mod = 1e9 + 9;
const int maxn = 500010;
const long double eps = 1e-5;
const int EPS = 500 * 500;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double,double> PDD;
template<typename T> void read(T &x) {
   x = 0;char ch = getchar();ll f = 1;
   while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
   while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args) {
   read(first);
   read(args...);
}
int arr[maxn];
struct node {
    int fa;//父亲
    int ch[2];// 存储左右儿子的位置
    int val;
    int rec;
    int sum;  
}T[N];
int tot = 0;
struct Splay {
    int root;
    
    void update(int x) {T[x].sum = T[ls(x)].sum + T[rs(x)].sum + T[x].rec;}

    int ident(int x) {return T[fa(x)].ch[0] == x ? 0 : 1;}

    void connect(int x, int fa, int how) {// 把x变成fa的how儿子
        T[fa].ch[how] = x;
        T[x].fa = fa;
    }

    void rotate(int x) { // 把x转到fa位置
        int Y = fa(x), R = fa(Y);
        int YSON = ident(x), RSON = ident(Y);
        connect(T[x].ch[YSON^1],Y,YSON);
        connect(Y,x,YSON^1);
        connect(x,R,RSON);
        update(Y);
        update(x);
    }

    void splay(int x, int to) { // 把x转到to的位置
        to = fa(to);
        while(fa(x) != to) {
            int y = fa(x);
            if(T[y].fa == to) rotate(x);
            else if(ident(x) == ident(y)) rotate(y), rotate(x);
            else rotate(x), rotate(x);
        }
    }

    int newnode(ll v, int f) {//开新节点
        T[++ tot].fa = f;
        T[tot].rec = T[tot].sum = 1;
        T[tot].val = v;
        return tot;
    } 

    void Insert(ll x) {//插入新的节点
        int now = root;
        if(root == 0) {newnode(x,0);root=tot;}
        else {
            while(1) {
                T[now].sum ++;
                if(T[now].val == x) {T[now].rec++;splay(now,root);return;}
                int nxt = x < T[now].val ? 0 : 1;
                if(!T[now].ch[nxt]) {
                    int p = newnode(x,now);
                    T[now].ch[nxt] = p;
                    splay(p,root);
                    root = p;
                    return;
                }
                now = T[now].ch[nxt];
            }
        }
    }

    int find(int x) {//查找x在哪里?
        int now = root;
        while(1) {
            if(!now) return now;
            if(T[now].val == x) {splay(now,root); root = now; return now;}
            int nxt = x < T[now].val ? 0 : 1;
            now = T[now].ch[nxt];
        }
    }

    int rak(int x) {
        int now = root, ans = 0;
        int las;
        while(now) {
            las = now;
            if(T[now].val == x) {
                ans = ans + T[T[now].ch[0]].sum + 1;
                splay(now,root);
                root = now;
                return ans;
            }
            int nxt = x < T[now].val ? 0 : 1;
            if(nxt == 1) ans = ans + T[T[now].ch[0]].sum + T[now].rec;
            now = T[now].ch[nxt];
        }
        splay(las,root), root = las;// 没有这句话会T飞了
        return ans;
    }

    void delet(int x) {
        int pos=find(x);
        if(!pos) return;
        if(T[pos].rec>1) {T[pos].rec--,T[pos].sum--;return ;} 
        else {
            if(!T[pos].ch[0]&&!T[pos].ch[1]) {root=0;return ;}
            else if(!T[pos].ch[0]) {root=T[pos].ch[1];T[root].fa=0;return ;}
            else
            {
                int left=T[pos].ch[0];
                while(T[left].ch[1]) left=T[left].ch[1];
                splay(left,T[pos].ch[0]);
                connect(T[pos].ch[1],left,1); 
                connect(left,0,1);
                root = left;
                update(left);
            }
        }
    }
}splay[N];

struct Segtree {
    int tr[N];
    int cnt[N];
    void pushup(int rt) {
        if(tr[rt<<1] == tr[rt<<1|1]) {
            tr[rt] = tr[rt<<1];
            cnt[rt] = cnt[rt<<1]+cnt[rt<<1|1];
        } else if(cnt[rt<<1] >= cnt[rt<<1|1]) {
            tr[rt] = tr[rt<<1];
            cnt[rt] = cnt[rt<<1] - cnt[rt<<1|1];
        } else {
            tr[rt] = tr[rt<<1|1];
            cnt[rt] = cnt[rt<<1|1] - cnt[rt<<1];
        }
    }
    void build(int rt, int l, int r) {
        if(l == r) {
            tr[rt] = arr[l];
            cnt[rt] = 1;
            return;
        }
        build(Lson);
        build(Rson);
        pushup(rt);
    }
    void update(int rt, int l, int r, int pos, int val) {
        if(l == r) {
            tr[rt] = val;
            cnt[rt] = 1;
            return;
        }
        if(pos <= mid) update(Lson,pos,val);
        else update(Rson,pos,val);
        pushup(rt);
    }
    PII ask(int rt, int l, int r, int posl, int posr) {
        if(posl <= l && posr >= r) return {tr[rt],cnt[rt]};
        PII res = {-INF,-INF};
        if(posl <= mid) res = ask(Lson,posl,posr);
        if(posr > mid) {
            PII ans = ask(Rson,posl,posr);
            if(res.first == -INF) return ans;
            if(ans.first == res.first) ans.second += res.second;
            else if(ans.second > res.second) ans.second -= res.second;
            else ans.first = res.first, ans.second = res.second - ans.second;
            return ans;
        }
        return res;
    }
}sgt;

int main() {
    IOS;
    int n, m;
    cin >> n >> m;
    for(int i = 1; i <= n; ++ i) splay[i].Insert(INF), splay[i].Insert(-INF);
    for(int i = 1; i <= n; ++ i) cin >> arr[i], splay[arr[i]].Insert(i);
    sgt.build(1,1,n);
    while(m--) {
        int l, r, s, k;
        cin >> l >> r >> s >> k;
        int pe = sgt.ask(1,1,n,l,r).first;
        int sum = splay[pe].rak(r) - splay[pe].rak(l-1);
        if(sum > (r-l+1)/2) cout << pe << endl, s = pe;
        else cout << s << endl;
        while(k --) {
            int x;
            cin >> x;
            splay[arr[x]].delet(x);
            splay[s].Insert(x);
            sgt.update(1,1,n,x,s);
            arr[x] = s;
        }
    }
    int last = sgt.ask(1,1,n,1,n).first;
    int sum = splay[last].rak(n)-1;
    if(sum>n/2) cout << last;
    else cout << "-1";
    return 0;
}
/*
2 2
1 1
2 2 2 1 2
1 2 1 1 1
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
当然可以,以下是一个简单的 Splay 平衡树实现代码(C++): ```c++ #include <iostream> using namespace std; struct Node { int val; Node *left, *right, *p; Node(int v) : val(v), left(nullptr), right(nullptr), p(nullptr) {} }; class SplayTree { private: Node *root; void left_rotate(Node *x) { Node *y = x->right; x->right = y->left; if (y->left != nullptr) { y->left->p = x; } y->p = x->p; if (x->p == nullptr) { root = y; } else if (x == x->p->left) { x->p->left = y; } else { x->p->right = y; } y->left = x; x->p = y; } void right_rotate(Node *x) { Node *y = x->left; x->left = y->right; if (y->right != nullptr) { y->right->p = x; } y->p = x->p; if (x->p == nullptr) { root = y; } else if (x == x->p->left) { x->p->left = y; } else { x->p->right = y; } y->right = x; x->p = y; } void splay(Node *x) { while (x->p != nullptr) { if (x->p->p == nullptr) { if (x == x->p->left) { right_rotate(x->p); } else { left_rotate(x->p); } } else if (x == x->p->left && x->p == x->p->p->left) { right_rotate(x->p->p); right_rotate(x->p); } else if (x == x->p->right && x->p == x->p->p->right) { left_rotate(x->p->p); left_rotate(x->p); } else if (x == x->p->right && x->p == x->p->p->left) { left_rotate(x->p); right_rotate(x->p); } else { right_rotate(x->p); left_rotate(x->p); } } } public: SplayTree() : root(nullptr) {} Node* search(int v) { Node *x = root; while (x != nullptr && x->val != v) { if (v < x->val) { x = x->left; } else { x = x->right; } } if (x != nullptr) { splay(x); } return x; } void insert(int v) { Node *z = new Node(v); Node *y = nullptr; Node *x = root; while (x != nullptr) { y = x; if (z->val < x->val) { x = x->left; } else { x = x->right; } } z->p = y; if (y == nullptr) { root = z; } else if (z->val < y->val) { y->left = z; } else { y->right = z; } splay(z); } void remove(int v) { Node *z = search(v); if (z == nullptr) { return; } if (z->left == nullptr) { transplant(z, z->right); } else if (z->right == nullptr) { transplant(z, z->left); } else { Node *y = minimum(z->right); if (y->p != z) { transplant(y, y->right); y->right = z->right; y->right->p = y; } transplant(z, y); y->left = z->left; y->left->p = y; } delete z; } Node* minimum(Node *x) { while (x->left != nullptr) { x = x->left; } return x; } Node* maximum(Node *x) { while (x->right != nullptr) { x = x->right; } return x; } void inorder_walk() { inorder_walk(root); cout << endl; } private: void transplant(Node *u, Node *v) { if (u->p == nullptr) { root = v; } else if (u == u->p->left) { u->p->left = v; } else { u->p->right = v; } if (v != nullptr) { v->p = u->p; } } void inorder_walk(Node *x) { if (x != nullptr) { inorder_walk(x->left); cout << x->val << ' '; inorder_walk(x->right); } } }; int main() { SplayTree tree; tree.insert(5); tree.insert(2); tree.insert(8); tree.insert(1); tree.insert(3); tree.insert(7); tree.insert(9); tree.inorder_walk(); // output: 1 2 3 5 7 8 9 tree.remove(5); tree.inorder_walk(); // output: 1 2 3 7 8 9 tree.search(7); tree.inorder_walk(); // output: 1 2 3 7 8 9 return 0; } ``` 以上代码实现了 Splay 平衡树的基本操作,包括插入、删除、查找、中序遍历等。如果你需要进一步了解 Splay 平衡树,可以参考相关资料。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值