题解:CF916D Jamie and To-do List

redacted-area / 2024-08-31 / 原文

题意

维护一个数据结构,支持以下几种操作:

  • set ai xi:设置任务 \(a_i\) 的优先级为 \(x_i\),如果该列表中没有出现则加入该任务。
  • remove a_i:删除该任务。
  • query a_i:求优先级比 \(a_i\) 小的任务个数,如果没有则输出 \(-1\)
  • undo sum:删除此次操作之前的 \(sum\) 次操作。

分析

前三个操作是非常典型的平衡树操作,考虑使用平衡树或者动态开点线段树。

第四个带撤回,考虑使用可持久化数据结构。

本篇题解使用可持久化动态开点线段树解决。

维护两棵线段树,一棵维护区间和用于记录优先级,一棵维护某任务是否存在。

注意本题强制在线,其他的内容就是板子。

AC 记录

Code

#include<bits/stdc++.h>
using namespace std;

namespace SegT
{
    struct node
    {
        int sum;
        node *lc, *rc;
        node() {memset(this, 0, sizeof *this);}
        void push_up() 
        {
            sum=0;
            if(lc) sum+=lc->sum;
            if(rc) sum+=rc->sum;
        }
    };

    #define lc(x) (x?x->lc:0)
    #define rc(x) (x?x->rc:0)
    #define mid ((l+r)>>1)
    #define lson x->lc, l, mid
    #define rson x->rc, mid+1, r

    void modify(node *pre, node *&x, int l, int r, int p, int v)
    {
        x=pre?new node(*pre):new node;
        if(l==r) return x->sum+=v, void();
        if(p<=mid) modify(lc(pre), lson, p, v);
        if(p>mid)  modify(rc(pre), rson, p, v);
        x->push_up();
    }

    int query(node *x, int l, int r, int L, int R)
    {
        if(!x) return 0;
        if(L<=l&&r<=R) return x->sum;
        int ret=0;
        if(L<=mid) ret+=query(lson, L, R);
        if(R>mid)  ret+=query(rson, L, R);
        return ret;
    }
}

namespace SegT2
{
    struct node
    {
        int v;
        node *lc, *rc;
        node() {memset(this, 0, sizeof *this);}
    };

    void build(node *&x, int l, int r)
    {
        x=new node;
        if(l==r) return;
        build(lson);
        build(rson);
    }

    void modify(node *pre, node *&x, int l, int r, int p, int v)
    {
        x=new node(*pre);
        if(l==r) return x->v=v, void();
        if(p<=mid) modify(pre->lc, lson, p, v);
        if(p>mid)  modify(pre->rc, rson, p, v);
    }

    int query(node *x, int l, int r, int p)
    {
        if(l==r) return x->v;
        if(p<=mid) return query(lson, p);
        if(p>mid)  return query(rson, p);
    }
}

unordered_map<string, int> ids;

SegT::node *rt[100005];
SegT2::node *exist[100005];

int main()
{
    ios::sync_with_stdio(0);
    int q, xi;
    const int n=1e9, m=1e5;
    cin>>q;
    string s, op;
    build(exist[0], 1, m);
    for(int i=1;i<=q;i++)
    {

        rt[i]=rt[i-1];
        exist[i]=exist[i-1];
        cin>>op;
        if(op[0]=='u')
        { 
            cin>>xi;
            rt[i]=rt[i-1-xi];
            exist[i]=exist[i-1-xi];
        }
        else
        {
            cin>>s;
            if(!ids.count(s)) ids[s]=ids.size()+1;
            int a=ids[s];
            if(op[0]=='s') 
            {
                cin>>xi;
                int va=query(exist[i], 1, m, a);
                if(va) modify(rt[i], rt[i], 1, n, va, -1);
                modify(exist[i], exist[i], 1, m, a, xi);
                modify(rt[i], rt[i], 1, n, xi, 1);
            }
            if(op[0]=='q') 
            {
                int ans=0;
                int va=query(exist[i], 1, m, a);
                if(va>1) ans=query(rt[i], 1, n, 1, va-1);
                if(!va) ans=-1;
                cout<<ans<<endl;
            }
            if(op[0]=='r') 
            {
                int va=query(exist[i], 1, m, a);
                if(!va) continue;
                modify(rt[i], rt[i], 1, n, va, -1);
                modify(exist[i], exist[i], 1, m, a, 0);
            }
        }
    }
}