玲珑杯 1072 - Capture(DFS序+线段树)

题目链接:点击打开链接

思路:

不难发现, 这是一棵树, 把树先建立好, 跑dfs序, 然后就变成了线段树区间修改、单点修改、区间最值。

细节参见代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <stack>
#include <ctime>
#include <bitset>
#include <cstdlib>
#include <cmath>
#include <set>
#include <list>
#include <deque>
#include <map>
#include <queue>
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
typedef long long ll;
typedef long double ld;
const double eps = 1e-6;
const double PI = acos(-1);
const int mod = 1000000000 + 7;
const int INF = 0x3f3f3f3f;
// & 0x7FFFFFFF
const int seed = 131;
const ll INF64 = ll(1e18);
const int maxn = 3e5 + 10;
int T, n, cnt_id = 0, dist[maxn];
vector<int> g[maxn];
char s[maxn];
struct node {
    char c;
    int v;
}a[maxn];
int tot;
void init() {
    cnt_id = 0;
    tot = 0;
    for(int i = 1; i <= n; i++) g[i].clear(), dist[i] = 0;
}
void cal() {
    int len = strlen(s);
    ++cnt_id;
    if(s[0] == '+') a[cnt_id].c = '+';
    else a[cnt_id].c = '-';
    a[cnt_id].v = 0;
    for(int i = 1; i < len; i++) {
        a[cnt_id].v = a[cnt_id].v * 10 + s[i]-'0';
    }
}
struct que {
    int id, v;
    que(int id=0, int v=0):id(id),v(v) {}
}maxv[maxn<<2];
int setv[maxn<<2];
que tal(que a, que b) {
    if(a.v < b.v) return b;
    else if(a.v == b.v) {
        if(a.id < b.id) return a;
        else return b;
    }
    else return a;
}
void pushup(int o) {
    maxv[o] = maxv[o<<1];
    if(maxv[o].v < maxv[o<<1|1].v) maxv[o] = maxv[o<<1|1];
    else if(maxv[o].v == maxv[o<<1|1].v && maxv[o].id > maxv[o<<1|1].id) maxv[o] = maxv[o<<1|1];
}
void pushdown(int l, int r, int o) {
    if(setv[o] != -1) {
        setv[o<<1] = setv[o<<1|1] = setv[o];
        maxv[o<<1] = maxv[o<<1|1] = que(INF, setv[o]);
        setv[o] = -1;
    }
}
void build(int l, int r, int o) {
    maxv[o] = que(1, 0);
    setv[o] = -1;
    if(l == r) return ;
    int mid = (l + r) >> 1;
    build(l, mid, o<<1);
    build(mid+1, r, o<<1|1);
}
void update(int L, int R, int id, int v, int l, int r, int o) {
    if(L <= l && r <= R) {
        maxv[o] = que(id, v);
        if(l != r) setv[o] = v;
        return ;
    }
    int mid = (l + r) >> 1;
    pushdown(l, r, o);
    if(L <= mid) update(L, R, id, v, l, mid, o<<1);
    if(mid < R) update(L, R, id, v, mid+1, r, o<<1|1);
    pushup(o);
}
que query(int L, int R, int l, int r, int o) {
    if(L <= l && r <= R) {
        return maxv[o];
    }
    int mid = (l + r) >> 1;
    pushdown(l, r, o);
    if(mid >= R) return query(L, R, l, mid, o<<1);
    else if(L > mid) return query(L, R, mid+1, r, o<<1|1);
    else {
        que cur1 = query(L, R, l, mid, o<<1);
        que cur2 = query(L, R, mid+1, r, o<<1|1);
        return tal(cur1, cur2);
    }
    pushup(o);
}
int in[maxn], out[maxn];
void dfs(int u, int fa) {
    in[u] = ++tot;
    int len = g[u].size();
    for(int i = 0; i < len; i++) {
        int v = g[u][i];
        dfs(v, u);
    }
    out[u] = tot;
}
int main() {
    scanf("%d",&T);
    while(T--) {
        scanf("%d", &n);
        init();
        int cnt_node = 1;
        for(int i = 1; i <= n; i++) {
            scanf("%s", s);
            cal();
            if(a[cnt_id].c == '+') {
                int v = a[cnt_id].v;
                g[v].push_back(++cnt_node);
            }
        }
        dfs(1, 0);
        build(1, cnt_node, 1);
        int cc = 1;
        for(int i = 1; i <= n; i++) {
            if(a[i].c == '+') {
                ++cc;
                int v = a[i].v;
                dist[cc] = dist[v]+1;
                update(in[cc], in[cc], cc, dist[v]+1, 1, cnt_node, 1);
            }
            else {
                int v = a[i].v;
                update(in[v], out[v], INF, -INF, 1, cnt_node, 1);
            }
            que ans = query(in[1], out[1], 1, cnt_node, 1);
            printf("%d\n", ans.id);
        }
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值