2019 icpc 南京网络赛 F Greedy Sequence 线段树

题意:给出原始序列a,a由1~n排列而成,要求构造以i为起点的满足一定条件的序列s使得字典序最大,s满足的条件时后面的数比前面的数小,并且这两个数在原序列中的位置小于k,输出i等于1~n的s的长度

题解:将原序列排序,依次加入线段树中,每次查询[pos[i]-k,pos[i]+k]中的最大值

#include <bits/stdc++.h>
#define FOR(i,s,t) for(int i=(s);i<=(t);i++)
#define ROF(i,s,t) for(int i=(s);i>=(t);i--)
#define pb push_back
#define mp make_pair
#define eb emplace_back
#define fi first
#define se second
#define endl '\n'
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int maxn = 1e5 + 6;
const int N = 1e5 + 5;
const ll mod = 998244353;
const ll mod2 = 998244352;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
int readInt(){
    int x=0;
    bool sign=false;
    char c=getchar();
    while(!isdigit(c)){
        sign=c=='-';
        c=getchar();
    }
    while(isdigit(c)){
        x=x*10+c-'0';
        c=getchar();
    }
    return sign?-x:x;
}
ll readLong(){
    ll x=0;
    bool sign=false;
    char c=getchar();
    while(!isdigit(c)){
        sign=c=='-';
        c=getchar();
    }
    while(isdigit(c)){
        x=x*10+c-'0';
        c=getchar();
    }
    return sign?-x:x;
}
string readString(){
    string s;
    char c=getchar();
    while(isspace(c)){
        c=getchar();
    }
    while(!isspace(c)){
        s+=c;
        c=getchar();
    }
    return s;
}
struct node{
    int id,val;
}a[maxn];

int M[maxn << 2];
int n , k;

bool cmp(node A, node B){
    return A.val < B.val;
}

void gather(int p){
    M[p] = max(M[p << 1] , M[p << 1 | 1]);
}

void update(int p , int l, int r, int pos, int val){
    if (l > r ) return;
    if (l == r && l == pos){
        M[p] += val;
        return ;
    }
    int mid = (l + r) / 2;
    if (pos <= mid) update(p << 1, l , mid, pos, val);
    else update(p << 1| 1, mid + 1, r, pos, val);
    gather(p);
}

int query(int p, int l, int r, int ql, int qr){
    if (l > qr || r < ql || l > r) return 0;
    if (ql <= l && r <= qr){
        return M[p];
    }
    int mid = (l + r ) / 2;
    return max(query(p<<1, l, mid, ql, qr) , query(p<<1|1, mid+1, r, ql, qr));
}
int ans[maxn];

int main(){
    int T = readInt();
    while (T--){
        n = readInt();
        k = readInt();
        FOR(i,1,n){
            a[i].val = readInt();
            a[i].id = i;
        }
        FOR(i,1,(n<<2)) M[i]=0;
        sort(a + 1, a + 1 + n, cmp);
        FOR(i,1, n){
            int ql = max(1, a[i].id - k);
            int qr = min(n, a[i].id + k);
            int tmp = query(1, 1, n, ql, qr);
            //cout << ql << " " << qr << endl;
            ans[i] = ans[tmp]+1;
            update(1,1,n,a[i].id,i);
        }
        FOR(i,1,n){
            printf("%d", ans[i]);
            if (i == n) putchar('\n');
            else putchar(' ');
        }
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值