Codeforces 46D Parking Lot(线段树)

题目链接:Codeforces 46D Parking Lot

题目大意:一个街道,长为N,每辆车停进来的时候必须和前面间隔B米,和后面间隔F米,现在用两种操作,1是停进来一个长为x的车,2是第x辆车开走。

解题思路:区间合并,建一颗长度为N + B + F的线段树,然后每次停车进去的时候都查询x + B + F的区间,然后修改的时候只修改x的长度。

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int maxn = 100505;

#define lson(x) ((x)<<1)
#define rson(x) (((x)<<1)|1)
int lc[maxn << 2], rc[maxn << 2], set[maxn << 2];
int L[maxn << 2], R[maxn << 2], S[maxn << 2]; 

inline int length(int u) {
    return rc[u] - lc[u] + 1;
}

inline void maintain (int u, int v) {
    S[u] = L[u] = R[u] = (v ? length(u) : 0);
}

inline void pushup (int u) {
    S[u] = max(max(S[lson(u)], S[rson(u)]), R[lson(u)] + L[rson(u)]);
    L[u] = L[lson(u)] + (L[lson(u)] == length(lson(u)) ? L[rson(u)] : 0);
    R[u] = R[rson(u)] + (R[rson(u)] == length(rson(u)) ? R[lson(u)] : 0);
}

inline void pushdown(int u) {
    if (set[u] != -1) {
        maintain(lson(u), set[u]);
        maintain(rson(u), set[u]);
        set[u] = -1;
    }
}

void build (int u, int l, int r) {
    lc[u] = l;
    rc[u] = r;
    set[u] = -1;

    if (l == r) {
        maintain(u, 1);
        return;
    }

    int mid = (l + r) / 2;
    build(lson(u), l, mid);
    build(rson(u), mid + 1, r);
    pushup(u);
}

void modify (int u, int l, int r, int v) {
    if (l <= lc[u] && rc[u] <= r) {
        maintain(u, v);
        return;
    }

    pushdown(u);
    int mid = (lc[u] + rc[u]) / 2;
    if (l <= mid)
        modify(lson(u), l, r, v);
    if (r > mid)
        modify(rson(u), l, r, v);
    pushup(u);
}

int query(int u, int k) {
    if (S[u] < k)
        return -1;

    if (lc[u] == rc[u])
        return lc[u];

    pushdown(u);
    int mid = (lc[u] + rc[u]) / 2, ret;
    if (S[lson(u)] >= k)
        ret = query(lson(u), k);
    else if (R[lson(u)] + L[rson(u)] >= k)
        ret = mid - R[lson(u)] + 1;
    else
        ret = query(rson(u), k);
    pushup(u);
    return ret;
}

int N, M, B, F;
int op[105][2];

int main () {
    scanf("%d%d%d%d", &N, &B, &F, &M);
    build(1, 0, B + F + N - 1);

    int x, y;
    for (int i = 1; i <= M; i++) {
        scanf("%d%d", &x, &y);
        if (x == 1) {
            op[i][0] = query(1, y + B + F);
            if (op[i][0] != -1) {
                //op[i][0] =
                op[i][1] = op[i][0] + y - 1;
                modify(1, op[i][0] + B, op[i][1] + B, 0);
            }
            printf("%d\n", op[i][0]);
        } else
            modify(1, op[y][0] + B, op[y][1] + B, 1);
    }
    return 0;
}
时间: 2024-10-23 08:32:57

Codeforces 46D Parking Lot(线段树)的相关文章

Codeforces 46D Parking Lot(贪心模拟)

Codeforces 46D Parking Lot 题目链接 开线段树专题开出了这题..看似要用区间合并求连续最大区间,其实不需要.因为询问才100个,直接set暴力去模拟即可,每次车进来就从左往右找到一个合适位置 代码: #include <cstdio> #include <cstring> #include <set> using namespace std; const int N = 100005; int L, b, f, n; set<int>

[Codeforces 1295E]Permutation Separation(线段树+贪心)

[Codeforces 1295E]Permutation Separation(线段树+贪心) 题面 给出一个排列\(p_1,p_2,...p_n\).初始时你需要选择一个位置把排列分成左右两个.然后在两个序列间移动元素使得左边序列的所有元素都比右边的所有元素小.给出每个元素\(p_i\)从一个序列移动到另一个序列的代价\(a_i\). 分析 显然最后得到的序列是小的数在一边,大的数在另一边.设从值为\(i\)的元素处分开之后移动代价为\(ans_i\). 一开始假设所有数都移到右边序列,那么

CF 46 D Parking Lot(线段树区间合并)

Description Nowadays it is becoming increasingly difficult to park a car in cities successfully. Let's imagine a segment of a street as long as L meters along which a parking lot is located. Drivers should park their cars strictly parallel to the pav

Codeforces 482B Interesting Array(线段树)

题目链接:Codeforces 482B Interesting Array 题目大意:给定一个长度为N的数组,现在有M个限制,每个限制有l,r,q,表示从a[l]~a[r]取且后的数一定为q,问是 否有满足的数列. 解题思路:线段树维护,每条限制等于是对l~r之间的数或上q(取且的性质,相应二进制位一定为1),那么处理完所有的 限制,在进行查询,查询对应每个l~r之间的数取且是否还等于q.所以用线段树维护取且和,修改为或操作. #include <cstdio> #include <c

Codeforces 755D(思维+线段树)

http://codeforces.com/problemset/problem/755/D 从X到X+k点,其实只要求从X到X+k之间的点有多少条线超过X--X+K这条线就行,一开始直接暴力,就时间超时了,而用线段树维护就快多了. 1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 #define N 1000010 5 #define INF 0x3f3f3f3f 6 #define lso

Codeforces 777D Hanoi Factory(线段树维护DP)

题目链接 Hanoi Factory 很容易想到这是一个DAG模型,那么状态转移方程就出来了. 但是排序的时候有个小细节:b相同时看a的值. 因为按照惯例,堆塔的时候肯定是内半径大的在下面. 因为N有1e5,那么DP的时候用线段树优化一下,就可以了. 1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define rep(i, a, b) for(int i(a); i <= (b); ++i) 6 7 typedef lo

CodeForces 91B Queue (线段树单点操作)

Description There are n walruses standing in a queue in an airport. They are numbered starting from the queue's tail: the 1-st walrus stands at the end of the queue and the n-th walrus stands at the beginning of the queue. The i-th walrus has the age

codeforces 522D. Closest Equals 线段树+离线

题目链接 n个数m个询问, 每次询问输出给定区间中任意两个相同的数的最近距离. 先将询问读进来, 然后按r从小到大排序, 将n个数按顺序插入, 并用map统计之前是否出现过, 如果出现过, 就更新线段树. 如果当前的i等于某个询问的r, 那么就查询, 具体看代码. 1 #include <iostream> 2 #include <vector> 3 #include <cstdio> 4 #include <cstring> 5 #include <

CodeForces 19D Points(线段树+map)

开始想不通,后来看网上说是set,就有一个想法是对每个x建一个set...然后又想直接建立两重的set就好,最后发现不行,自己想多了...  题意是给你三种操作:add (x y) 平面添加(x y)这个点 remove (x y)平面删除(x y)这个点 find (x y) 查找(x y)这个点严格的右上方中最左边的点,有多个就再找最下方的点,输出 其实想通了还是比较简单的,我的想法就是对于x先排序再对y排序,这样建一颗线段树,用处在于:添加和删除都可以当成单点更新,只需要记录最大值就好.f