Irrigation【codeforces1181D】【可持久化线段树维护第K小+二分搜索】

Codeforces Round #567 (Div. 2).D


D. Irrigation

time limit per test

2.5 seconds

memory limit per test

512 megabytes

input

standard input

output

standard output

Misha was interested in water delivery from childhood. That's why his mother sent him to the annual Innovative Olympiad in Irrigation (IOI). Pupils from all Berland compete there demonstrating their skills in watering. It is extremely expensive to host such an olympiad, so after the first ?n olympiads the organizers introduced the following rule of the host city selection.

The host cities of the olympiads are selected in the following way. There are ?m cities in Berland wishing to host the olympiad, they are numbered from 11 to ?m. The host city of each next olympiad is determined as the city that hosted the olympiad the smallest number of times before. If there are several such cities, the city with the smallest index is selected among them.

Misha's mother is interested where the olympiad will be held in some specific years. The only information she knows is the above selection rule and the host cities of the first ?n olympiads. Help her and if you succeed, she will ask Misha to avoid flooding your house.

Input

The first line contains three integers ?n, ?m and ?q (1≤?,?,?≤5000001≤n,m,q≤500000) — the number of olympiads before the rule was introduced, the number of cities in Berland wishing to host the olympiad, and the number of years Misha's mother is interested in, respectively.

The next line contains ?n integers ?1,?2,…,??a1,a2,…,an (1≤??≤?1≤ai≤m), where ??ai denotes the city which hosted the olympiad in the ?i-th year. Note that before the rule was introduced the host city was chosen arbitrarily.

Each of the next ?q lines contains an integer ??ki (?+1≤??≤1018n+1≤ki≤1018) — the year number Misha's mother is interested in host city in.

Output

Print ?q integers. The ?i-th of them should be the city the olympiad will be hosted in the year ??ki.


  这题是上个月的了,那时候一直在忙于考试的准备,打完比赛之后一直没有补上,现在终于过了,期间真的要错到自闭了……QAQ是我太弱了,有时候对于状态想的还不够全面。

  一开始的时候(先讲了下当时比赛TLE on 10的思路),因为我想到最后的时候会达到一个稳态,所以我想的是用一棵线段树去维护区间上最小的被覆盖过的点,使得它进入下一个平衡态时候的所需要的次数。所以要离线查询。然后嘛,时间太大了啊,T了啊…… 

比赛的时候,还超级开心的以为会A,尤其是一下子就到test 10的时候。

接下去的时候,讲一下正解(解法不唯一,大家也可以自己去推一下不一样的)。

  我们知道一开始有了N次的放入,那么我们也同样的知道了,最后达成从(City1 ~ CityM)这样的顺序选择的话,我们可能得走N层,把前N层都放满。举个例子,一开始过了6年,为「3年1,2年2,1年3」,有4座城市,这样子的情况时候,我们知道,当我们把第3层取完的时候,(因为有3个是1)之后一定会进入“稳态”。但是,有时候不想去劳烦再去处理一下最大值的问题,所以我们干脆可以直接取到第6层(也就是第N层),然后之后的都叫做稳态了。

  怎样处理呢,我画一张图来表示一下,

City从1~M。每个City在一开始的时候(因为有N年这个先决条件),有其出现的次数cnt[i],我们要去填充它们。

那么,我们填充的每一层有怎样的条件呢?我来用红笔来标示出怎样的是层:

红色的,就是某一层。

  看到红色的长度,会受到我们需要覆盖的长度的影响,那么,层数越高,也代表着需要更多的“空空”来覆盖上去,第一层的“空空”是什么呢?把第一层填满,那么所需要的就是所有cnt[i] == 0的i的个数;再往下,第二层,填满需要的是cnt[i] == 0和cnt[i] == 1的总和,…… ,往下都是不断的加起来,所以我们得这样累加一下,可以看成是不断的加上cnt[i - 1] == 0的i的个数的前缀和。

  但是这样的话,好像还是很难维护,我想我们还得知道这时候跑到了第几层,那么,是不是我们可以二分搜索来得到这个答案,直接去将每一层的累加,(这里开了个名叫dp的数组)dp[i] = dp[i-1] + pre;(pre指的就是前一段的那个前缀和)。

  那么,我们就可以找到它是第几层的,以及是不是超出了N层,达到了稳态?

  但是这里还有个小心的地方,到达稳态之后的处理,也不要忘记再去剪掉dp[N]。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
#define MP3(a, b, c) MP(MP(a, b), c)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int maxN = 5e5 + 7;
int N, M, Q, cnt[maxN], rt[maxN], lc[maxN * 25], rc[maxN * 25], tree[maxN * 25], tot = 0;
ll dp[maxN];
vector<int> vt[maxN];
inline void Insert(int &now, int old, int l, int r, int qx)
{
    now = ++tot; tree[now] = tree[old] + 1; lc[now] = lc[old]; rc[now] = rc[old];
    if(l == r) return;
    int mid = HalF;
    if(qx <= mid) Insert(lc[now], lc[old], l, mid, qx);
    else Insert(rc[now], rc[old], mid + 1, r, qx);
}
inline int Query(int rt, int l, int r, int k)
{
    if(l == r) return l;
    int mid = HalF;
    if(tree[lc[rt]] >= k) return Query(lc[rt], l, mid, k);
    else return Query(rc[rt], mid + 1, r, k - tree[lc[rt]]);
}
int main()
{
    scanf("%d%d%d", &N, &M, &Q);
    for(int i=1, u; i<=N; i++)
    {
        scanf("%d", &u);
        cnt[u]++;
    }
    for(int i=1; i<=M; i++) vt[cnt[i]].push_back(i);
    dp[0] = 0;  //第0层
    ll pre = 0;
    for(int i=0, len; i<=N + 1; i++) //最多叠至N层之后就是一定会进入一个所谓的稳态(一定会是(K - dp[N] - N - 1)%M + 1)这样的形式
    {
        if(i) dp[i] = dp[i - 1] + pre;
        len = (int)vt[i].size();
        pre += len;    //这一层所多出来的部分
        if(i) rt[i] = rt[i-1];
        for(int j=0; j<len; j++) Insert(rt[i], rt[i], 1, M, vt[i][j]);
    }
    ll Kth;
    int pos;
    while(Q--)
    {
        scanf("%lld", &Kth);
        Kth -= N;
        pos = (int)(lower_bound(dp + 1, dp + N + 1, Kth) - dp);
        if(pos == N + 1) printf("%d\n", (int)((Kth - dp[N] - 1) % M + 1));  //这里一定要减去dp[N]是为了知道从哪一步开始就进入了平衡的状态
        else printf("%d\n", Query(rt[pos - 1], 1, M, Kth - dp[pos - 1]));
    }
    return 0;
}
/*
1 100 1
5
101
ans:1

1 100 1
1
101
ans:1
 */

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wuliwuliii

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值