【Codeforces813E】軍隊の創造|思考、会長ツリー

件名リンク:https//codeforces.com/contest/813/problem/E

本旨:

長さがNのシーケンスが与えられると、Q回の照会が実行され、
各照会内で強制的にオンラインになります[l、r](cntはiの発生数を表します):
∑ min(cnti、k)\ sum {min(cnt_i、k)}m i n c n tk

トピックのアイデア

この質問は、間隔内の異なる数
数に似ています。議長ツリーまたはツリーのような配列で実装できます。
その質問の実装方法を検討してください记录某个数上一次出现的位置
同じように、この質問はその質問に似ていますが、必要性:记录某个数前面第k次出现的位置
これにより、発生数がkを超えないことが保証
されます。議長ツリーを使用して維持することをお勧めします。

コード:

/*** 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