[線段樹] Chef and Array

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,r
using 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");
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章