CodeForces1180E.Serge and Dining Room(线段树)

                                                 E. Serge and Dining Room

time limit per test

4 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

Serge came to the school dining room and discovered that there is a big queue here. There are mm pupils in the queue. He's not sure now if he wants to wait until the queue will clear, so he wants to know which dish he will receive if he does. As Serge is very tired, he asks you to compute it instead of him.

Initially there are nn dishes with costs a1,a2,…,ana1,a2,…,an. As you already know, there are the queue of mm pupils who have b1,…,bmb1,…,bm togrogs respectively (pupils are enumerated by queue order, i.e the first pupil in the queue has b1b1 togrogs and the last one has bmbm togrogs)

Pupils think that the most expensive dish is the most delicious one, so every pupil just buys the most expensive dish for which he has money (every dish has a single copy, so when a pupil has bought it nobody can buy it later), and if a pupil doesn't have money for any dish, he just leaves the queue (so brutal capitalism...)

But money isn't a problem at all for Serge, so Serge is buying the most expensive dish if there is at least one remaining.

Moreover, Serge's school has a very unstable economic situation and the costs of some dishes or number of togrogs of some pupils can change. More formally, you must process qq queries:

  • change aiai to xx. It means that the price of the ii-th dish becomes xx togrogs.
  • change bibi to xx. It means that the ii-th pupil in the queue has xx togrogs now.

Nobody leaves the queue during those queries because a saleswoman is late.

After every query, you must tell Serge price of the dish which he will buy if he has waited until the queue is clear, or −1−1 if there are no dishes at this point, according to rules described above.

Input

The first line contains integers nn and mm (1≤n,m≤300 0001≤n,m≤300 000) — number of dishes and pupils respectively. The second line contains nnintegers a1,a2,…,ana1,a2,…,an (1≤ai≤1061≤ai≤106) — elements of array aa. The third line contains mm integers b1,b2,…,bmb1,b2,…,bm (1≤bi≤1061≤bi≤106) — elements of array bb. The fourth line conatins integer qq (1≤q≤300 0001≤q≤300 000) — number of queries.

Each of the following qq lines contains as follows:

  • if a query changes price of some dish, it contains 11, and two integers ii and xx (1≤i≤n1≤i≤n, 1≤x≤1061≤x≤106), what means aiai becomes xx.
  • if a query changes number of togrogs of some pupil, it contains 22, and two integers ii and xx (1≤i≤m1≤i≤m, 1≤x≤1061≤x≤106), what means bibi becomes xx.

Output

For each of qq queries prints the answer as the statement describes, the answer of the ii-th query in the ii-th line (the price of the dish which Serge will buy or −1−1 if nothing remains)

Examples

input

Copy

1 1
1
1
1
1 1 100

output

Copy

100

input

Copy

1 1
1
1
1
2 1 100

output

Copy

-1

input

Copy

4 6
1 8 2 4
3 3 6 1 5 2
3
1 1 1
2 5 10
1 1 6

output

Copy

8
-1
4

Note

In the first sample after the first query, there is one dish with price 100100 togrogs and one pupil with one togrog, so Serge will buy the dish with price 100100 togrogs.

In the second sample after the first query, there is one dish with price one togrog and one pupil with 100100 togrogs, so Serge will get nothing.

In the third sample after the first query, nobody can buy the dish with price 88, so Serge will take it. After the second query, all dishes will be bought, after the third one the third and fifth pupils will by the first and the second dishes respectively and nobody will by the fourth one.

 

一、原题地址

点我传送

 

二、大致题意

给出a序列为各种食物的价格,b序列为小朋友拥有的钱,小朋友依次购买食物,每个人都买自己能买的起的最贵的食物,买不起就离开队伍。给出q次操作,操作1是修改食物的价格,操作2是修改小朋友的钱,每次操作后询问当小朋友买完之后,能买到的最贵的食物的价格是多少,没有食物了就输出-1。

 

三、大致思路

对于每个食物,在[ 1,ai ]范围上都加上1 ,对于每个小朋友,在 [ 1,bi ]上都减去1.

每个询问实际上就是在寻找这个前缀和出现大于0的最大的位置。

那么在线段树查询操作时,如果发现右子树存在这样的解那么肯定就是优先右子树;否则才考虑左子树。



四、代码

#include<iostream>
#include<cstring>
#include<vector>
#include<deque>
#include<algorithm>
using namespace std;
typedef long long LL;
const int inf=0x3f3f3f3f;


int n,m;
const int N=6e5+5;
int a[N],b[N],v[3*N];
int sum;
struct Que
{
    int ty,p,val;
}q[N];


LL  lazy[N << 2];			//lazy用来记录该节点的每个数值应该加多少
struct Tree
{
	int l, r;
	LL sum;
	int mid()
	{
		return (l + r) >> 1;
	}
}tree[N<<2];		//tree[].l, tree[].r分别表示某个节点的左右区间,这里的区间是闭区间

void PushUp(int rt)
{
	tree[rt].sum = max(tree[rt << 1].sum , tree[rt << 1 | 1].sum);
}

void PushDown(int rt,int m)
{
	if (lazy[rt]!=0)
	{
		lazy[rt << 1] += lazy[rt];
		lazy[rt << 1 | 1] += lazy[rt];
		tree[rt << 1].sum += lazy[rt];
		tree[rt << 1 | 1].sum += lazy[rt];
		lazy[rt] = 0;
	}
}

void build(int l, int r, int rt)
{
	tree[rt].l = l;
	tree[rt].r = r;
	lazy[rt] = 0;
	if (l == r)
	{
		tree[rt].sum = 0;
		return;
	}
	int m = tree[rt].mid();
	build(l, m, (rt << 1));
	build(m + 1, r, (rt << 1 | 1));
	PushUp(rt);
}

void update(int c, int l, int r, int rt)//表示对区间[l,r]内的每个数均加c,rt是根节点
{
	if (tree[rt].l == l&&tree[rt].r==r)
	{
		lazy[rt] += c;
		tree[rt].sum += c;
		return;
	}
	if (tree[rt].l == tree[rt].r)return;
	int m = tree[rt].mid();
	PushDown(rt, tree[rt].r - tree[rt].l + 1);
	if (r <= m)update(c, l, r, rt << 1);
	else if (l > m)update(c, l, r, rt << 1 | 1);
	else
	{
		update(c, l, m, rt << 1);
		update(c, m + 1, r, rt << 1 | 1);
	}
	PushUp(rt);
}

LL Query(int l, int r, int rt)
{
    //printf("**%d  %d  sum:%d\n",tree[rt].l,tree[rt].r,tree[rt].sum);
	if (tree[rt].l==tree[rt].r)
	{
		return tree[rt].l;
	}
	int m = tree[rt].mid();
	PushDown(rt, tree[rt].r - tree[rt].l + 1);
	if(tree[rt<<1|1].sum>0)return Query(m+1,r,rt<<1|1);
	else return Query(l,m,rt<<1);
}


int main()
{
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        v[++sum]=a[i];
    }
    for(int i=1;i<=m;i++)
    {
        scanf("%d",&b[i]);
        v[++sum]=b[i];
    }
    int Q;
    scanf("%d",&Q);
    for(int i=1;i<=Q;i++)
    {
        scanf("%d %d %d",&q[i].ty,&q[i].p,&q[i].val);
        v[++sum]=q[i].val;
    }
    sort(v+1,v+1+sum);
    sum=unique(v+1,v+1+sum)-v-1;
    for(int i=1;i<=n;i++)a[i] = lower_bound(v+1,v + sum+1,a[i]) -v;
    for(int i=1;i<=m;i++)b[i] = lower_bound(v+1,v + sum+1,b[i]) -v;
    for(int i=1;i<=Q;i++)q[i].val= lower_bound(v+1,v + sum+1,q[i].val) -v;

    build(1,sum,1);
    for(int i=1;i<=n;i++)update(1,1,a[i],1);
    for(int i=1;i<=m;i++)update(-1,1,b[i],1);
    //printf("q1:%d\n",Query(1,1,1));
    for(int i=1;i<=Q;i++)
    {
        if(q[i].ty==1)
        {
            update(-1,1,a[q[i].p],1);
            a[q[i].p]=q[i].val;
            update(1,1,a[q[i].p],1);
        }
        else
        {
            update(1,1,b[q[i].p],1);
            b[q[i].p]=q[i].val;
            update(-1,1,b[q[i].p],1);
        }
        if(tree[1].sum<=0)printf("-1\n");
        else printf("%d\n",v[Query(1,sum,1)]);
    }





return 0;


}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值