D. Jamie and To-do List

Problem - D - Codeforces

D. Jamie and To-do List

time limit per test

2 seconds

memory limit per test

512 megabytes

input

standard input

output

standard output

Why I have to finish so many assignments???

Jamie is getting very busy with his school life. He starts to forget the assignments that he has to do. He decided to write the things down on a to-do list. He assigns a value priority for each of his assignment (lower value means more important) so he can decide which he needs to spend more time on.

After a few days, Jamie finds out the list is too large that he can't even manage the list by himself! As you are a good friend of Jamie, help him write a program to support the following operations on the to-do list:

  • set ai xi — Add assignment ai to the to-do list if it is not present, and set its priority to xi. If assignment ai is already in the to-do list, its priority is changed to xi.
  • remove ai — Remove assignment ai from the to-do list if it is present in it.
  • query ai — Output the number of assignments that are more important (have a smaller priority value) than assignment ai, so Jamie can decide a better schedule. Output  - 1 if ai is not in the to-do list.
  • undo di — Undo all changes that have been made in the previous di days (not including the day of this operation)

At day 0, the to-do list is empty. In each of the following q days, Jamie will do exactly one out of the four operations. If the operation is a query, you should output the result of the query before proceeding to the next day, or poor Jamie cannot make appropriate decisions.

Input

The first line consists of a single integer q (1 ≤ q ≤ 105) — the number of operations.

The following q lines consists of the description of the operations. The i-th line consists of the operation that Jamie has done in the i-th day. The query has the following format:

The first word in the line indicates the type of operation. It must be one of the following four: set, remove, query, undo.

  • If it is a set operation, a string ai and an integer xi follows (1 ≤ xi ≤ 109). ai is the assignment that need to be set to priority xi.
  • If it is a remove operation, a string ai follows. ai is the assignment that need to be removed.
  • If it is a query operation, a string ai follows. ai is the assignment that needs to be queried.
  • If it is a undo operation, an integer di follows (0 ≤ di < i). di is the number of days that changes needed to be undone.

All assignment names ai only consists of lowercase English letters and have a length 1 ≤ |ai| ≤ 15.

It is guaranteed that the last operation is a query operation.

Output

For each query operation, output a single integer — the number of assignments that have a priority lower than assignment ai, or  - 1 if ai is not in the to-do list.

Interaction

If the operation is a query, you should output the result of the query and flush the output stream before proceeding to the next operation. Otherwise, you may get the verdict Idleness Limit Exceed.

For flushing the output stream, please refer to the documentation of your chosen programming language. The flush functions of some common programming languages are listed below:

  • C: fflush(stdout);
  • C++: cout « flush;
  • Java: System.out.flush();

Examples

input

Copy

8
set chemlabreport 1
set physicsexercise 2
set chinesemockexam 3
query physicsexercise
query chinesemockexam
remove physicsexercise
query physicsexercise
query chinesemockexam

output

Copy

1
2
-1
1

input

Copy

8
set physicsexercise 2
set chinesemockexam 3
set physicsexercise 1
query physicsexercise
query chinesemockexam
undo 4
query physicsexercise
query chinesemockexam

output

Copy

0
1
0
-1

input

Copy

5
query economicsessay
remove economicsessay
query economicsessay
undo 2
query economicsessay

output

Copy

-1
-1
-1

input

Copy

5
set economicsessay 1
remove economicsessay
undo 1
undo 1
query economicsessay

output

Copy

-1

算是一道模拟题,建立两个可持久化线段树,值域虽然1e9,但我们最多2e5个数据,每次动态开点,空间不会爆掉。

对于每个事物的优先级建立一个可持久化线段树,对于各种优先级事物的出现次数建立一个线段树,判断条件多但不复杂,模拟即可。

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

int lson1[200000*40+10],rson1[200000*40+10];
int lson2[200000*40+10],rson2[200000*40+10];
int val[200000*40+10],sum[200000*40+10];
map<string,int>mp;
int nowid;
int root1[200000+10],root2[200000+10];
int getid(string s)
{
    if(mp.find(s)!=mp.end())
        return mp[s];
    nowid++;
    mp[s]=nowid;
    return nowid;
}

int tot1,tot2;

int clone1(int root)
{
    tot1++;
    lson1[tot1]=lson1[root];
    rson1[tot1]=rson1[root];
    val[tot1]=val[root];
    return tot1;
}

int change1(int root,int l,int r,int pos,int nowval)
{

    root=clone1(root);

    if(l==r)
    {
        val[root]=nowval;
        return root;
    }
    int mid=(l+r)>>1;
    if(pos<=mid)
        lson1[root]=change1(lson1[root],l,mid,pos,nowval);
    else
        rson1[root]=change1(rson1[root],mid+1,r,pos,nowval);
    return root;


}

int getval(int root,int l,int r,int pos)
{
    if(l==r)
    {
        return val[root];
    }
    int mid=(l+r)>>1;
    if(pos<=mid)
        return getval(lson1[root],l,mid,pos);
    else
        return getval(rson1[root],mid+1,r,pos);
}

int clone2(int root)
{
    tot2++;
    lson2[tot2]=lson2[root];
    rson2[tot2]=rson2[root];
    sum[tot2]=sum[root];
    return tot2;
}

int change2(int root,int l,int r,int pos,int add)
{

    root=clone2(root);
    if(l==r)
    {
        sum[root]+=add;
        return root;
    }
    int mid=(l+r)>>1;

    if(pos<=mid)
        lson2[root]=change2(lson2[root],l,mid,pos,add);
    else
        rson2[root]=change2(rson2[root],mid+1,r,pos,add);

    sum[root]=(sum[lson2[root]]+sum[rson2[root]]);
    return root;
}
int getsum(int root,int l,int r,int L,int R)
{
    if(L<=l&&r<=R)
    {
        return sum[root];
    }

    int mid=(l+r)>>1;

    int ans=0;
    if(L<=mid)
        ans+=getsum(lson2[root],l,mid,L,R);
    if(R>mid)
        ans+=getsum(rson2[root],mid+1,r,L,R);
    return ans;

}
int main()
{

    int t;
    cin>>t;


    for(int i=1; i<=t; i++)
    {
        string s;
        cin>>s;
        if(s=="set")
        {
            string now;
            cin>>now;
            int id=getid(now);
            int nowval;
            scanf("%d",&nowval);
            int temp=getval(root1[i-1],1,1e9,id);
            if(temp==0)
            {
                root2[i]=change2(root2[i-1],1,1e9,nowval,1);
            }
            else
            {
                root2[i]=change2(root2[i-1],1,1e9,temp,-1);
                root2[i]=change2(root2[i],1,1e9,nowval,1);
            }
            root1[i]=change1(root1[i-1],1,1e9,id,nowval);
        }
        else if(s=="remove")
        {
            string now;
            cin>>now;
            int id=getid(now);
            int pre=getval(root1[i-1],1,1e9,id);
            root1[i]=change1(root1[i-1],1,1e9,id,0);

            if(pre)
                root2[i]=change2(root2[i-1],1,1e9,pre,-1);
            else
                root2[i]=root2[i-1];
        }
        else if(s=="query")
        {
            root1[i]=root1[i-1];
            root2[i]=root2[i-1];
            string now;
            cin>>now;
            int id=getid(now);
            int pos=getval(root1[i],1,1e9,id);
            if(pos==1||pos==0)
            {
                if(pos==1)
                {
                    cout<<0<<endl;
                }
                else
                {
                    cout<<-1<<endl;
                }
                continue;
            }
            int nowans=getsum(root2[i],1,1e9,1,pos-1);
            cout<<nowans<<endl;
        }
        else
        {
            int x;
            cin>>x;
            root1[i]=root1[i-x-1];
            root2[i]=root2[i-x-1];
        }
    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秦三码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值