Codeforces 387E George and Cards 树状数组 + 集合set查询

题目大意:

就是现在有n章卡片的排列p1, p2...pn, 每张卡片上写着1~n, 现在George进行n - k次remove的操作, 使得最后只剩下的牌为b1, b2...bk, 每次remove操作可以选择一段连续的区间x1, x2...xw, 然后从中移除最小的那个, 注意移除最小的那个之后剩下的卡片保持连在一起, 完成这样一次操作会得到w份香肠, 为了使最后剩下的牌的排列为b1, b2, b3 ... bk, 应该怎样选使得得到的香肠最多, 输出最多能得到的香肠份数


大致思路:

先找到贪心的思路然后就是用树状数组维护一下了...注意set当中upper_bound函数和lower_bound函数的区别


代码如下:

Result  :  Accepted     Memory  :  71500 KB     Time  :  1497 ms

/*
 * Author: Gatevin
 * Created Time:  2015/3/10 15:12:18
 * File Name: Kotori_Itsuka.cpp
 */
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;

/*
 * 首先不难想到贪心的思想, 每次选择移除能够移除的最小的那个数
 * 这样多次选择之后区间长度综合才最大
 */
int n, k;
int pos[1000010];//数值为i的数的位置pos[i]
bool keep[1000010];//最后i是否需要留下来为keep[i]
int C[1000010];
set<int> S, T;//集合S中是需要保留的位置, 并且变化, 随着贪心接下来要选择移除的数而变化

//树状数组维护方便查询某区间当中已经被移除的数
int lowbit(int x)
{
    return -x & x;
}

void add(int x, int value)
{
    while(x <= n)
        C[x] += value, x += lowbit(x);
    return;
}

int ask(int L, int R)
{
    int ret = 0;
    while(R)
        ret += C[R], R -= lowbit(R);
    while(L)
        ret -= C[L], L -= lowbit(L);
    return ret;
}

int main()
{
    scanf("%d %d", &n, &k);
    int tmp;
    for(int i = 1; i <= n; i++)
        scanf("%d", &tmp), pos[tmp] = i;
    for(int i = 1; i <= k; i++)
        scanf("%d", &tmp), keep[tmp] = 1;
    S.insert(0); S.insert(n + 1);
    T.insert(0); T.insert(-n - 1);
    lint ans = 0;
    for(int i = 1; i <= n; i++)//贪心思想枚举接下来要选择删除的数
        if(keep[i])
            S.insert(pos[i]), T.insert(-pos[i]);
        else
        {
            int R = *S.upper_bound(pos[i]);
            //int L = *S.lower_bound(pos[i] - 1);
            //low_bound(x)返回的是不比x小的第一个数的地址, 不是小于x的最大的
            int L = -*T.upper_bound(-pos[i]);
            ans += (R - L - 1);
            ans -= ask(L, R - 1);//这段区间(L, R)当中已经被删除的元素
            add(pos[i], 1);
        }
    printf("%I64d\n", ans);
    return 0;
}


你可能感兴趣的:(树状数组,codeforces,and,George,cards,387E)