【题解】【LibreOJ Round #6】花团 LOJ 534 时间线段树分治 背包

本文介绍了一种使用时间线段树分治解决特定问题的方法,并提供了详细的代码实现。通过对物品插入和查询操作的优化,实现了高效的时间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Prelude

题目链接:萌萌哒传送门(/≧▽≦)/


Solution

如果完全离线的话,可以直接用时间线段树分治来做,复杂度\(O(qv \log q)\)
现在在线了怎么办呢?
这其实是个假在线,因为每个物品的删除时间已经给你了,所以还是直接用时间线段树分治来做。
其实我是重点想谈一下复杂度的,\(O(n^{2} \log n)\)的复杂度居然都可以出到\(15000\),而且居然还跑的飞快?

1085857-20171106091120794-571327606.jpg


Code

#include <cstring>
#include <algorithm>
#include <cstdio>
#include <utility>
#include <vector>

using namespace std;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
typedef long double ldouble;
typedef pair<int,int> pii;
typedef vector<pii>::iterator viter;
const int MAXN = 15010;
const int LOGN = 17;
const int INF = 0x3f3f3f3f;
int _w;

inline void bmin( int &a, int b ) {
    a = b < a ? b : a;
}
inline void bmax( int &a, int b ) {
    a = b > a ? b : a;
}

int q, maxv, T, lastans;

struct Knapsack {
    int f[MAXN];
    void init() {
        for( int i = 0; i <= maxv; ++i )
            f[i] = -INF;
        f[0] = 0;
    }
    void insert( int v, int w ) {
        for( int i = maxv-v; i >= 0; --i )
            bmax( f[i+v], f[i]+w );
    }
    const int &operator[]( int i ) const {
        return f[i];
    }
    int &operator[]( int i ) {
        return f[i];
    }
};

vector<pii> item[MAXN<<2];
Knapsack f[LOGN];
int qv[MAXN];

pii ins;
int ql, qr;
void insert( int o, int L, int R ) {
    if( L >= ql && R <= qr ) {
        item[o].push_back(ins);
    } else {
        int M = (L+R)>>1, lc = o<<1, rc = lc|1;
        if( ql <= M ) insert(lc, L, M);
        if( qr > M ) insert(rc, M+1, R);
    }
}
void query( int i, int d ) {
    if( qv[i] != -1 ) {
        int v = qv[i];
        if( f[d][v] < 0 ) {
            puts("0 0");
            lastans = 0;
        } else {
            printf( "1 %d\n", f[d][v] );
            lastans = T * (f[d][v] ^ 1);
        }
    }
    if( i == q ) return;
    int op;
    _w = scanf( "%d", &op );
    if( op == 1 ) {
        int v, w, e;
        _w = scanf( "%d%d%d", &v, &w, &e );
        v -= lastans, w -= lastans, e -= lastans;
        ins = pii(v, w), ql = i+1, qr = e;
        insert(1, 0, q);
    } else {
        _w = scanf( "%d", qv+i+1 );
        qv[i+1] -= lastans;
    }
}
void solve( int o, int L, int R, int d ) {
    for( viter it = item[o].begin(); it != item[o].end(); ++it )
        f[d].insert(it->first, it->second);
    if( L == R ) {
        query(L, d);
    } else {
        int M = (L+R)>>1, lc = o<<1, rc = lc|1;
        f[d+1] = f[d];
        solve(lc, L, M, d+1);
        f[d+1] = f[d];
        solve(rc, M+1, R, d+1);
    }
}

int main() {
    _w = scanf( "%d%d%d", &q, &maxv, &T );
    f[0].init();
    memset(qv, -1, sizeof qv);
    solve(1, 0, q, 0);
    return 0;
}

转载于:https://www.cnblogs.com/mlystdcall/p/7791623.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值