【Codeforces 813E】Army Creation | 思维、主席树

题目链接:https://codeforces.com/contest/813/problem/E

题目大意:

给出一个序列,长度为N,进行Q次询问,强制在线
每次询问[l,r]内(cnt表示i出现的次数):
∑ m i n ( c n t i , k ) \sum{min(cnt_i,k)} min(cnti,k)

题目思路

这题与区间内不同数字的种数类似
可以用主席树、或者树状数组进行实现
考虑那题的实现方法:记录某个数上一次出现的位置
所以同样的,这题与那题类似,只需要:记录某个数前面第k次出现的位置
这样就保证了出现次数不可能超过k
这里用主席树维护就好了

Code:

/*** keep hungry and calm CoolGuang!  ***/
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define d(x) printf("%lld\n",x);
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const ll INF= 1e17;
const ll maxn = 3e5+700;
const int mod= 1e9+7;
const int up = 1e9;
template<typename T>inline void read(T &a){
    
    char c=getchar();T x=0,f=1;while(!isdigit(c)){
    
    if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){
    
    x=(x<<1)+(x<<3)+c-'0';c=getchar();}a=f*x;}
ll n,m,p;
vector<int>b[maxn];
int pos[maxn];
struct node{
    
    
    int l,r;
    int w;
}t[maxn*30];
int root[maxn*30];
int cnt = 0;
void Insert(int &now,int pre,int l,int r,int pos,int w){
    
    
    t[now = ++cnt] = t[pre];
    t[now].w += w;
    if(l == r) return ;
    int mid = (l+r)/2;
    if(pos <= mid) Insert(t[now].l,t[pre].l,l,mid,pos,w);
    else Insert(t[now].r,t[pre].r,mid+1,r,pos,w);
}
ll Find(int now,int l,int r,int pos){
    
    
    if(l == r) return t[now].w;
    int mid = (l+r)/2;
    if(pos <= mid) return Find(t[now].l,l,mid,pos) + t[t[now].r].w;
    return Find(t[now].r,mid+1,r,pos);
}
int main(){
    
    
    read(n);read(m);
    for(int i=1;i<=n;i++){
    
    
        int x;read(x);
        Insert(root[i],root[i-1],1,n,i,1);
        b[x].push_back(i);
        if(b[x].size()>m){
    
    
            Insert(root[i],root[i],1,n,b[x][pos[x]],-1);
            pos[x]++;
        }
    }
    read(p);
    int last = 0;
    for(int i=1;i<=p;i++){
    
    
        int l,r;read(l);read(r);
        l = (last+l)%n+1,r = (last+r)%n+1;
        if(l>r) swap(l,r);
        last = Find(root[r],1,n,l);
        printf("%d\n",last);
    }
    return 0;
}

/***
10
0101011101
****/

猜你喜欢

转载自blog.csdn.net/qq_43857314/article/details/111591972