[线段树] Chef and Array

来源:互联网 发布:因为你是范晓萱 知乎 编辑:程序博客网 时间:2024/05/16 13:50

CHEFLKJ: Chef and Array
题目描述
大厨喜欢序列和有关序列的一切。他称一个序列 V 是支配的,当且仅当存在一个数字 x(即“支配者”)其在序列中的出现次数严格超过序列长度的一半(即 ⌊|V |/2⌋)。
他的朋友 Dmytro 想让大厨开心,因此他给大厨呈现了这道有趣的题目:
给定序列 A,你需要处理 Q 个询问。询问分为两类:
• 1 x y:令序列的第 x 个元素的值为 y,即令 Ax = y;
• 2 l r:询问子序列 A[l..r] 是否是支配的,如果是则输出“Yes”,否则输出“No”。
输入格式
输入的第一行包含两个整数 N 和 Q,分别代表 A 中的元素数和需要处理的询问数。
第二行包含 N 个由空格分隔的整数,代表序列 A。
接下来 Q 行,每行描述一个询问。
输出格式
对于每个第 2 类的询问,输出一行,包含询问的回答。
数据范围
• 1 ≤ N, Q ≤ 10^5
• 1 ≤ Ai,y ≤ 10^9
• 1 ≤ x ≤ N
• 1 ≤ l ≤ r ≤ N

分析:
先用线段树+map树套树暴力存所有数,然后更新就是经典的单点更新,再处理查询。
假设x是[l,r]的支配者,根据鸽巢原理,x也必须是左儿子的支配者,或者是右儿子的支配者(否则x的个数必然不超过长度的一半,矛盾),然后发现这只是个必要条件,而非充分条件,即左右儿子的支配者不一定是节点的支配者,所以查询的时候往左右找到所有支配者,暴力判断是不是支配者。
似乎并不用启发式合并。

#include<bits/stdc++.h>#define lson rt<<1,l,mid#define rson rt<<1|1,mid+1,rusing namespace std;const int N = 1e5+5;unordered_map<int,int>tree[N<<2];int domi[N<<2];int a[N];void push_up(int rt, int len){    int lrt = rt<<1, rrt = rt<<1|1;    if(tree[rt][domi[lrt]] > len) domi[rt] = domi[lrt];    else if(tree[rt][domi[rrt]] > len) domi[rt] = domi[rrt];    else domi[rt] = -1;}void build(int rt, int l, int r){    if(l == r){        tree[rt][a[l]]++;        domi[rt] = a[l];        return;    }    int mid = (l+r)>>1;    build(lson);    build(rson);    tree[rt] = tree[rt<<1];    for(auto x : tree[rt<<1|1]) tree[rt][x.first] += x.second;    push_up(rt, (r-l+1)/2);}void update(int rt, int l, int r, int pos, int pre, int val){    if(l == r){        tree[rt].clear();        a[pos] = val;        tree[rt][val]++;        domi[rt] = val;        return;    }    int mid = (l+r) >> 1;    if(pos <= mid) update(lson, pos, pre, val);    else update(rson, pos, pre, val);    tree[rt][pre] -= 1;    tree[rt][val] += 1;    push_up(rt, (r-l+1)/2);}vector<int>qry;void query(int rt, int l, int r, int ql, int qr){    if(ql <= l && qr >= r){ qry.push_back(rt); return; }    int mid = (l+r)>>1;    if(ql <= mid) query(lson, ql, qr);    if(qr > mid) query(rson, ql, qr);}int main(){    int n, q;    scanf("%d%d", &n, &q);    for(int i = 1; i <= n; ++i) scanf("%d", a+i);    build(1, 1, n);    while(q--){        int t, x, y;        scanf("%d%d%d", &t, &x, &y);        if(t == 1) update(1, 1, n, x, a[x], y);        else{            int flag = 0;            qry.clear();            query(1, 1, n, x, y);            for(int i = 0; i < qry.size() && !flag; ++i){                int cnt = 0;                for(int j = 0; j < qry.size() && !flag; ++j){                    cnt += tree[qry[j]][domi[qry[i]]];                }                if(cnt > (y-x+1)/2){                    puts("Yes");                    flag = 1;                    break;                }            }            if(!flag) puts("No");        }    }}
0 0
原创粉丝点击