Codeforces Round #567 (Div. 2) D. Irrigation(思维+主席树)

题目链接
大意:m个城市,给你前n年的举办城市,之后的每一年都会让举办次数最少且标号最小的城市举办一次,给你q组询问让你求出第k年的举办城市。
思路:首先,对m个城市按举办次数从小到达排序,建一颗主席树,然后每次举办的城市显然是在一些举办次数相同且最小的城市中轮换,那我们就预处理出每种等级的城市升级到下一个等级一共需要多少次(按举办次数分等级),然后每次询问就二分一下是从哪个等级升过来的,然后在主席树上查一下区间第x小就行了。
细节有一些需要注意:

#include<bits/stdc++.h>

#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define LL long long
#define pii pair<int,int>
#define SZ(x) (int)x.size()
#define all(x) x.begin(),x.end()

using namespace std;

LL gcd(LL a, LL b) {return b ? gcd(b, a % b) : a;}
LL lcm(LL a, LL b) {return a / gcd(a, b) * b;}
LL powmod(LL a, LL b, LL MOD) {LL ans = 1; while (b) {if (b % 2)ans = ans * a % MOD; a = a * a % MOD; b /= 2;} return ans;}
const int N = 5e5 + 3;
const LL mod = 1e9 + 7;
int n,m,q;
int a[N],b[N],cnt;
LL sum[N];
vector<int>v[N];
int T[N];
struct faker{int sum,l,r;}t[N*40];
struct uzi{int a,i;bool operator <(const uzi &t)const{return a<t.a;}}p[N];
int NOW;
void up(int &x,int y,int l,int r,int pos){
    t[++NOW]=t[y];t[NOW].sum++;x=NOW;
    if(l==r)return ;
    int mid=l+r>>1;
    if(pos<=mid)up(t[x].l,t[y].l,l,mid,pos);
    else up(t[x].r,t[y].r,mid+1,r,pos);
}
int get(int x,int y,int l,int r,int k){
    if(l==r)return l;
    int res=t[t[y].l].sum-t[t[x].l].sum;
    int mid=l+r>>1;
    if(res>=k)return get(t[x].l,t[y].l,l,mid,k);
    else return get(t[x].r,t[y].r,mid+1,r,k-res);
}
int tot[N];
int main() {
	ios::sync_with_stdio(false);
    cin>>n>>m>>q;
    for(int i=1;i<=m;i++)p[i].i=i;
    for(int i=1;i<=n;i++)cin>>a[i],b[i]=a[i],p[a[i]].a++,p[a[i]].i=a[i];
    sort(b+1,b+1+n);
    sort(p+1,p+1+m);
    int level=0;p[0].a=-1;
    for(int i=1;i<=m;i++){
        if(p[i].a!=p[i-1].a)level++;
        v[level].pb(p[i].i);
        up(T[i],T[i-1],1,m,p[i].i);
    }
    for(int i=1;i<=level;i++)tot[i]=tot[i-1]+SZ(v[i]);
    int l=1;
    while(l<=m){
        LL res=b[l];int pre=l;
        while(l+1<=m&&p[l+1].a==p[l].a)++l;
        if(l!=m){
            sum[++cnt]=1ll*l*p[l+1].a-1ll*l*p[l].a+sum[cnt-1];//升级到下一个需要的
        }else break;
        l++;
    }
    for(int i=1;i<=q;i++){
        LL x;cin>>x;x-=n;
        if(!cnt){
            x%=m;if(!x)x=m;
            cout<<get(T[0],T[m],1,m,x)<<endl;
        }else{
            int pos=lower_bound(sum+1,sum+1+cnt,x)-sum;
            if(pos>cnt){
                x-=sum[cnt];x%=m;if(!x)x=m;
                cout<<get(T[0],T[m],1,m,x)<<endl;
            }else{
                x-=sum[pos-1];x%=tot[pos];if(!x)x=tot[pos];
                cout<<get(T[0],T[tot[pos]],1,m,x)<<endl;
            }
        }
    }
	return 0;
}
全部评论

相关推荐

06-02 15:53
阳光学院 Java
点赞 评论 收藏
分享
ALEX_BLX:虾皮好像去年秋招就很抽象,根本不知道要人的标准是啥,而且即使hr面完了也有可能泡不出来池子
投递虾皮信息等公司10个岗位
点赞 评论 收藏
分享
07-25 11:26
清华大学 Java
打开电脑,思绪又回到了7月份刚开始的时候,感觉这个月过的如梦如幻,发生了太多事,也算是丰富了我本就是平淡的人生吧太早独立的我习惯了一切都是自己做决定,拥有绝对的决定权,而且永远不会听取别人的建议。我就是那个恋爱四年出轨的男主啦,感觉既然在牛客开了这个头,那我就要做个有始有终的人。从我出轨到结束再到和女朋友和好如初真的太像一场梦了,短短的一个月我经历了太多,也成长了很多,放下了那些本就不属于我的,找回了那些我不该放弃的。我的人生丰富且多彩,但人不能一直顺,上天总会让你的生活中出点乱子,有好有坏,让你学会一些东西,让你有成长。我和女朋友的恋爱四年太过于平淡,日常除了会制造一些小浪漫之外,我们的生活...
段哥亡命职场:不得不说,我是理解你的,你能发出来足见你是个坦诚的人,至少敢于直面自己的内心和过往的过错。 这个世界没有想象中那样非黑即白,无论是农村还是城市,在看不见的阴影里,多的是这样的事。 更多的人选择站在制高点去谩骂,一方面是社会的道德是需要制高点的,另一方面,很多人不经他人苦,却劝他人善。 大部分的我们,连自己生命的意义尚且不能明晰,道德、法律、困境,众多因果交织,人会迷失在其中,只有真的走出来之后才能看明白,可是没走出来的时候呢?谁又能保证自己能走的好,走的对呢? 可是这种问题有些人是遇不到的,不去追寻,不去探寻,也就没了这些烦恼,我总说人生的意义在过程里,没了目标也就没了过程。 限于篇幅,没法完全言明,总之,这世界是个巨大的草台班子,没什么过不去了,勇敢面对,革故鼎新才是正确,祝你早日走出来。查看图片
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务