• (线段树)CF813 Educational Codeforces Round 22 E


    E. Army Creation
    time limit per test
    2 seconds
    memory limit per test
    256 megabytes
    input
    standard input
    output
    standard output

    As you might remember from our previous rounds, Vova really likes computer games. Now he is playing a strategy game known as Rage of Empires.

    In the game Vova can hire n different warriors; ith warrior has the type ai. Vova wants to create a balanced army hiring some subset of warriors. An army is called balanced if for each type of warrior present in the game there are not more than k warriors of this type in the army. Of course, Vova wants his army to be as large as possible.

    To make things more complicated, Vova has to consider q different plans of creating his army. ith plan allows him to hire only warriors whose numbers are not less than li and not greater than ri.

    Help Vova to determine the largest size of a balanced army for each plan.

    Be aware that the plans are given in a modified way. See input section for details.

    Input

    The first line contains two integers n and k (1 ≤ n, k ≤ 100000).

    The second line contains n integers a1, a2, ... an (1 ≤ ai ≤ 100000).

    The third line contains one integer q (1 ≤ q ≤ 100000).

    Then q lines follow. ith line contains two numbers xi and yi which represent ith plan (1 ≤ xi, yi ≤ n).

    You have to keep track of the answer to the last plan (let's call it last). In the beginning last = 0. Then to restore values of li and ri for the ith plan, you have to do the following:

    1. li = ((xi + lastmod n) + 1;
    2. ri = ((yi + lastmod n) + 1;
    3. If li > ri, swap li and ri.
    Output

    Print q numbers. ith number must be equal to the maximum size of a balanced army when considering ith plan.

    Example
    Input
    6 2
    1 1 1 2 2 2
    5
    1 6
    4 3
    1 1
    2 6
    2 6
    Output
    2
    4
    1
    3
    2
    Note

    In the first example the real plans are:

    1. 1 2
    2. 1 6
    3. 6 6
    4. 2 4
    5. 4 6

    首先计算每个编号的士兵前第k个与其类型相同的人的位置。对于这个士兵所在的查询区间[l,r],如果上述前面那个人的位置小于l则这个士兵在[l,r]中同类型人的编号中一定小于k,即可以计算。

    计算出上述的prek数组后,对其建立线段树以方便查询。线段树维护区间中的所有prek,维护成有序的形式,之后查询时直接使用lower_bound函数即可。

    维护有序形式时,利用stl中的merge函数,将一个结点的两个子节点代表的区间合并即可。

    merge函数的用法(第一个容器的起始位置,第一个容器的末位置,第二个容器的起始位置,第二个容器的末位置,存储合并完的容器的起始位置,(可有可无)cmp函数)

    注意使用merge之前要对存储合并结果的容器进行resize操作,不然会报错。

     1 #include <iostream>
     2 #include <string>
     3 #include <algorithm>
     4 #include <cstring>
     5 #include <cstdio>
     6 #include <cmath>
     7 #include <queue>
     8 #include <set>
     9 #include <map>
    10 #include <list>
    11 #include <vector>
    12 #include <stack>
    13 #define mp make_pair
    14 //#define P make_pair
    15 #define MIN(a,b) (a>b?b:a)
    16 //#define MAX(a,b) (a>b?a:b)
    17 typedef long long ll;
    18 typedef unsigned long long ull;
    19 const int MAX=1e5+5;
    20 const int MAX_V=1e3+5;
    21 const ll INF=4e18+5;
    22 const double M=4e18;
    23 using namespace std;
    24 const int MOD=1e9+7;
    25 typedef pair<ll,int> pii;
    26 const double eps=0.000000001;
    27 #define rank rankk
    28 int la[MAX],prek[MAX];
    29 vector<int>num[MAX<<2],cnt[MAX];
    30 void build(int l,int r,int k)
    31 {
    32     if(l==r)
    33     {
    34         num[k].push_back(prek[l]);
    35         return;
    36     }
    37     int mid=(l+r)/2;
    38     build(l,mid,2*k);
    39     build(mid+1,r,2*k+1);
    40     num[k].resize(num[2*k].size()+num[2*k+1].size());
    41     merge(num[2*k].begin(),num[2*k].end(),num[2*k+1].begin(),num[2*k+1].end(),num[k].begin());
    42     return;
    43 }
    44 inline int query(int l,int r,int ql,int qr,int x,int k)
    45 {
    46     if(ql<=l&&qr>=r)
    47         return lower_bound(num[k].begin(),num[k].end(),x)-num[k].begin();
    48     int mid=(l+r)/2;
    49     int re=0;
    50     if(ql<=mid)
    51         re+=query(l,mid,ql,qr,x,2*k);
    52     if(qr>mid)
    53         re+=query(mid+1,r,ql,qr,x,2*k+1);
    54     return re;
    55 }
    56 int n,k,tem;
    57 int main()
    58 {
    59     scanf("%d%d",&n,&k);
    60     for(int i=1;i<=n;i++)
    61     {
    62         scanf("%d",&tem);
    63         cnt[tem].push_back(i);
    64         if(cnt[tem].size()>k)
    65             prek[i]=cnt[tem][cnt[tem].size()-k-1];
    66     }
    67     int m,an=0;
    68     build(1,n,1);
    69     scanf("%d",&m);
    70     while(m--)
    71     {
    72         int x,y;
    73         scanf("%d%d",&x,&y);
    74         x=(x+an)%n+1;
    75         y=(y+an)%n+1;
    76         if(y<x)
    77             swap(x,y);
    78         an=query(1,n,x,y,x,1);
    79         printf("%d
    ",an);
    80     }
    81     return 0;
    82 }
  • 相关阅读:
    java 之 对象与垃圾回收
    Java 之 内部类
    java 接口(interface)
    抽象类
    Java之fianl修饰符
    类的继承
    上传图片
    一般处理程序 给图片添加文字水印
    socket
    初识linq,lambda表达式
  • 原文地址:https://www.cnblogs.com/quintessence/p/6953453.html
Copyright © 2020-2023  润新知