【可持久化线段树】[COCI]白雪公主(white)

题目描述:
白雪公主和N个小矮人住在森林里。每天早上,矮人们排成一队出去挖矿的路上,白雪公主就负责给他们拍照,并把这些照片传到社交网络上去。
白雪每次都会拍很多照片,她要从中选出一些完美的照片。小矮人们都戴着不同颜色的
帽子。如果照片上小矮人们有一半以上人戴着相同颜色的帽子,则这张照片就算是完美的。
也就是说,如果照片上有K个人,如果有多于K/2的人带着相同颜色的帽子,则这张照片就是完美的。
现在,写一个程序来检测相片集M是不是完美的,并且判断出完美照片上,哪种是主要的颜色。
输入:
第一行包含2个整数N和C(3≤N≤300000,1≤C≤10000),矮人的数目和帽子颜色的种类。
第二行包含N个1到C的整数,表示帽子的颜色,按照矮人们走路的先后顺序给出。
第三行包含M(1≤M≤10000),表示照片的数目。
接下来M行包含2个整数A,B(1≤A≤B≤N)。每一行描述了一张照片,照片上有第A个人到第B个人。
输出:
M行,如果那张照片不完美,则输出“no”,否则输出“yes X”,X表示照片上主要的颜色。
30%的数据,M小于10.
30%的数据,C小于10.
样例输入:
10 3
1 2 1 2 1 2 3 2 3 3
8
1 2
1 3
1 4
1 5
2 5
2 6
6 9
7 10
样例输出:
no
yes 1
no
yes 1
no
yes 2
no
yes 3

首先用可持久化线段树统计到i个之前的每一个的出现次数,然后每一次询问的时候用位于B的那个树的左子树.sum 减去A-1的树的左子树.sum可以得到左子树的颜色的总的在[A,B]区间内的出现次数如果这都已经小雨了L/2那么答案的颜色一定不再左子树中,然后同样的检查右子树,如果还是小于L/2那么一定是无解的,因为只是向下询问所以复杂度为O(log2C×m)其中C为颜色的种类,m为询问的次数

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
typedef long long LL;
const LL MAXT = 4500000;
const LL MAXN = 300000;
struct Node{
    LL lch, rch;
    LL sum;
    Node(){sum = lch = rch = 0;}
}Tree[MAXT+10];
LL rts[MAXN+10], ttot;
inline LL mid(LL l, LL r){return l + ((r - l) >> 1);}
void Insert(LL &now, LL val, LL l, LL r){
    if(val < l || val > r) return ;
    Tree[++ttot] = Tree[now];
    now = ttot;
    Tree[now].sum++;
    if(l == r) return ;
    if(val <= mid(l, r)) Insert(Tree[now].lch, val, l, mid(l,r));
    else Insert(Tree[now].rch, val, mid(l,r)+1, r);
}
int ans;
bool Query(LL now, LL up, LL L, LL R, LL least){
    if(L == R){
        ans = L;
        return true;
    }
    int _mid = mid(L, R);
    if(Tree[Tree[now].lch].sum - Tree[Tree[up].lch].sum > least)
        if(Query(Tree[now].lch, Tree[up].lch, L, _mid, least))
            return true;
    if(Tree[Tree[now].rch].sum - Tree[Tree[up].rch].sum > least)
        if(Query(Tree[now].rch, Tree[up].rch, _mid+1, R, least))
            return true;
    ans = -1;
    return false;
}
int main(){
    int n, C, tmp, A, B;
    scanf("%d%d", &n, &C);
    for(int i=1;i<=n;i++){
        scanf("%d", &tmp);
        rts[i] = rts[i-1];
        Insert(rts[i], tmp, 1, C);
    }
    int m;
    scanf("%d", &m);
    for(int i=1;i<=m;i++){
        scanf("%d%d", &A, &B);
        Query(rts[B], rts[A-1], 1, C, (B-A+1)/2);
        if(ans == -1) printf("no\n");
        else printf("yes %d\n", ans);
    }

    return 0;
}

转载于:https://www.cnblogs.com/JeremyGJY/p/5921663.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值