csu:1914: John and his party

Description

John is very popular ,he often holds parties with his friends.Today is a sunny day,it seems hold a bonefire party is a good idea.So John open his phone book and invites his friends in order. As we know, someone likes noisy place and some maybe oppisite.So when John calls his friends,his friends will always ask him”How many people will be there?If more than/less than ...,I will not come.” Now John want to know if he wants to invite exactly k people ,how many friends he has to call?

Input

The input file will contain one or more cases. The first line contains a single integer n (1 ≤ n ≤ 200000) — the number of phonenumber in John’s phone book. Each of the next n lines contains two integers ai and bi (0<=ai<=1,1≤ bi ≤ n) ai==0 means the i-th John’s friend will come if there are at most bi prople will be in the party(including the i-th friend himself/herself) ai==1 means the i-th John’s friend will come if there are at least bi prople will be in the party(including the i-th friend himself/herself)

John will call his friends by the order of the phonenumber in his phone book.

Output

Output n space-separated integers. The k-th number should be equal to the number of friends called by John if he wants to invite exactly k people to the party. If for some k the party cannot be arranged, output  - 1 for this k.

Sample Input

6
0 3
1 2
1 6
0 4
1 4
0 6

Sample Output

1 2 4 6 -1 -1
题目大意:
给出n个人的信息下x,y,x代表y是上限还是下限,0时为上限,1为下限,然后输出n个数,对于第i个数,输出的是前几个人的信息刚好包含i,i次
思路:
最容易想到的就是对于输出的第i个数,就去遍历一遍n个人,时间复杂度时n^2的,如果细心体会的话,就能知道输出的n个数就相当于n次查询啊,而n个人的信息就相当于
n次更新,加上数据这么大,我们可以想到跟线段树有关,那么怎么去构造出这颗线段树呢,对于线段树来说,他的叶子结点就是一段序列的初始值,那么我么先考虑这段序列的
构造,我们可以想到输出的n个数,输出的时被前几个区间刚好覆盖为i次,那么我们可以想到序列构造为a[i] = -i,即表示i位置还需要被覆盖i次,当a[i]等于0时即满足答案
现在已经构造出了叶子结点,剩下的就是往上传递什么了,由于一开始的初始值都是负值,我们需要知道每次更新后那个节点为0,那么可以想到传递的是每一段区间的最大值
每一次更新之后查看根结点的值是否为0,如果为0那么就将这个位置的答案ans[i] = i,那么还有一个问题,就是我们怎么知道为0的节点是哪一个位置的,那么我们可以再开一颗
记录位置的的线段树根据mx线段数同步更新这样,id[1]就代表了mx[1]的位置,最后有个小细节需要注意,就是当一个位置变为0后,我们需要将他变为-inf,以防影响后面的答案
ac代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<sstream>
#include<vector>
#include<cmath>
#define LL long long
#define md int mid = (L+R)>>1
#define ls rt<<1
#define rs rt<<1|1
using namespace std;
const int maxn = 2e5+50000;
int id[maxn<<2],mx[maxn<<2];
int n;
int ans[maxn];
int lazy[maxn<<2];
void push_up(int rt)
{
    if(mx[ls]>=mx[rs])
        id[rt] = id[ls];
    else
        id[rt] = id[rs];
    mx[rt] = max(mx[ls],mx[rs]);
}
void push_down(int rt)
{
    if(lazy[rt])
    {
        lazy[ls] += lazy[rt];
        lazy[rs] += lazy[rt];
        mx[ls] += lazy[rt];
        mx[rs] += lazy[rt];
        lazy[rt] = 0;
    }
}
void build(int L,int R,int rt)
{
    if(L==R)
    {
        id[rt] = L;
        mx[rt] = -L;
        return ;
    }
    md;
    build(L,mid,ls);
    build(mid+1,R,rs);
    push_up(rt);
}
void update(int l,int r,int L,int R,int rt)
{
   // cout<<"diap"<<endl;
    if(l<=L&&R<=r)
    {
        lazy[rt]++;
        mx[rt]++;
        return ;
    }
    push_down(rt);
    md;
    if(l<=mid)
        update(l,r,L,mid,ls);
    if(r>mid)
        update(l,r,mid+1,R,rs);
    push_up(rt);
}
void change(int p,int L,int R,int rt)
{
    if(L==R)
    {
        mx[rt] = -0x3f3f3f3f;
       // id[rt] = L;
        return ;
    }
    md;
    push_down(rt);
    if(mid>=p)
        change(p,L,mid,ls);
    else
        change(p,mid+1,R,rs);
    push_up(rt);

}
int main()
{
    while(~scanf("%d",&n))
    {
        memset(ans,-1,sizeof(ans));
        build(1,n,1);
        memset(lazy,0,sizeof(lazy));
        for(int i = 0 ;i < n;i++)
        {
            int op,x;
            scanf("%d%d",&op,&x);
            if(!op)
            {
                //cout<<"fuck"<<endl;
                update(1,x,1,n,1);
            //cout<<"gan"<<endl;
            }
            else
                update(x,n,1,n,1);
            if(mx[1]<0)
                continue;
            while(!mx[1])
            {
                ans[id[1]] = i+1;
                change(id[1],1,n,1);
            }
        }
        for(int i = 1;i <= n;i++ )
            printf("%d%c",ans[i],i==n?'\n':' ');
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值