Monkeying Around Gym - 101350F

题意:

When the monkey professor leaves his class for a short time, all the monkeys go bananas. N monkeys are lined up sitting side by side on their chairs. They each have the same joke book. Before the professor returns, M jokes were heard.

Each of the M jokes are said in the order given and have the following properties:

xi - position of the monkey who said it.

li – index of the joke in the book.

ki – volume the monkey says that joke.

When the monkey at position xi says the joke li, all monkeys at a distance less than or equal to ki from that monkey (including the monkey who said the joke) will fall off their chairs in laughter if they have never heard the joke li before.

If the joke li has been heard anytime during the past before, and the monkey hears it again, then he will sit back up in his chair.

A monkey can fall off his chair more than once (every time he hears a new joke), and if he is already on the ground and hears a new joke, he will stay on the ground.

Can you figure out how many monkeys will be in their seats by the time the professor comes back?


思路:这个题有两种做法,其中一种使用线段树的做法,用两棵线段树,第一棵用于记录最后听到的笑话编号,第二棵用于记录某一个位置听到某一笑话几次。

第二种是一种很巧妙的方法,主要是思路,先对所有的笑话进行处理,在能听到这个笑话的两个端点进行处理,然后在对每一个猴子进行处理,用set保存当前能被听到的笑话个数,如果在当前这个位置的猴子是听到这个笑话的左端点,就把这个笑话放入set中,如果在当前这个位置恰好是听不到这个笑话的位置就把这个笑话进行删除,如果当前set中没有任何笑话,那么这个猴子一定是坐在凳子上的,如果说这个猴子最后的那个笑话听过多次,那么这个猴子也是坐在凳子上的,其他情况猴子在地上。

#include <bits/stdc++.h>
using  namespace  std;
const int maxn=1e5+50;
struct Node
{
    int x,y,idx,num;
} e[maxn];
int num[maxn];
struct Nodes
{
    int idx,num;
    bool operator<(const Nodes &n1) const
    {
        if(n1.idx==idx) return num<n1.num;
        return idx<n1.idx;
    }
};
set<Nodes> sd;
vector<int> v[maxn];
set<Nodes>::iterator it;
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        memset(num,0,sizeof(num));
        sd.clear();
        for(int i=0; i<=n; i++) v[i].clear();
        for(int i=1; i<=m; i++)
        {
            int x,l,k;
            scanf("%d%d%d",&x,&l,&k);
            e[i].idx=i;
            e[i].num=l;
            e[i].y=min(n,x+k);
            e[i].x=max(1,x-k);
            v[e[i].y+1].push_back(-i);
            v[e[i].x].push_back(i);
        }
        int ans=0;
        for(int i=1; i<=n; i++)
        {
            for(int j=0; j<v[i].size(); j++)
            {
                if(v[i][j]>0)
                {
                    num[e[v[i][j]].num]++;
                    sd.insert((Nodes)
                    {
                        e[v[i][j]].idx,e[v[i][j]].num
                    });
                }
                else
                {
                    num[e[-v[i][j]].num]--;
                    sd.erase((Nodes)
                    {
                        e[-v[i][j]].idx,e[-v[i][j]].num
                    });
                }
            }
            if(sd.size()==0) ans++;
            else
            {
                it=sd.end();
                it--;
                if(num[(*it).num]!=1) ans++;
            }
        }
        cout<<ans<<endl;
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值