Gym 100960G Youngling Tournament(splay)

185 篇文章 0 订阅
7 篇文章 0 订阅

Description

standard input/output
Statements

Yoda, the Grand Master of the Jedi Order, hit on the idea to hold a tournament among younglings. He has not chosen the date yet, but he has already decided on the format of the tournament.

There are N younglings studying in the Jedi Temple. Yoda can feel the Force inside younglings, moreover, he can represent the amount of the Force inside i-th youngling as the number fi.

Therefore, the format of the tournament is the following. At first, Yoda makes the children stand in a row in order of non-increasing fi. Then, the first youngling in the row competes against all the others united together. The combat is based on lightsaber battle and is very spectacular. However, Yoda knows that the result doesn't depend on anything but the Force inside competitors. The youngling wins if his amount of Force is not less than the total amount of the Force inside all his opponents. In that case, he is considered one of the winners. Otherwise, he loses. Anyway, after that he is removed from the row, and the tournament continues. Again, the strongest (first in the row) youngling competes against all the others standing in the row in the same format, if he wins, he is also considered one of the winners. After that he is removed and the tournament continues in the same format until there is only one child in the row. He becomes one of the winners automatically and the tournament finishes.

Yoda wants to know the total number of winners. However, as the tournament is postponed again and again, the amount of the Force inside the younglings changes from time to time. Help Yoda to compute the total number of winners after each change.

Input

The first line of input contains a single integer N, the number of younglings in the Jedi Temple (1 ≤ N ≤ 100 000).

The second line contains N integers f1, f2, ..., fN the amount of the Force inside the younglings (1 ≤ fi ≤ 1012).

The third line of the input contains a single integer M, the number of changes in the Force amounts of students (0 ≤ M ≤ 50 000).

The next M lines contain information about the changes. The i-th of these lines describes the i-th change and contains two integers k and fk * , which mean that the amount of the Force inside the k-th youngling becomes equal to fk *  (1 ≤ k ≤ N, 1 ≤ fk *  ≤ 1012).

Output

Print M + 1 lines, each of them containing a single integer.

On the first line, print the number of winners if the tournament was held before all the changes. On line (i + 1) for all i > 0, print the number of winners if the tournament was held after the first i changes.

Sample Input

Input
3
2 1 3
3
1 3
2 7
3 5
Output
3
2
3
2
Input
7
2 14 14 15 5 2 5
5
5 2
4 12
5 4
3 10
7 9
Output
4
3
3
3
3
4



题意:给n个数,m次修改操作,每次把一个数换成另一个数,每次修改后问将原序列从小到大排序后,不小于它前边所有数个数有多少个。


分析:很显然这种数最多有log(10^12)个,于是我们可以用splay维护这个序列,然后每次在splay中查找符合条件的数,splay中最左边的数必定符合条件,设以它开始的前缀和为v,那么下一个符合条件的数至少为v,这样继续在splay中查找,每个询问最多找不到40次。


#include<iostream>
#include<string>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<set>
#include<map>
#include<vector>
#include<cstring>
#include<stack>
#include<cmath>
#include<queue>
#include <unordered_map>
#define INF 21474836470000
#define eps 1e-9  
#define MOD 1000000007 
#define MAXN 150010  
using namespace std;  
typedef long long ll;
int pre[MAXN],ch[MAXN][2],root,tot,n,m,q;  
ll sum[MAXN],key[MAXN],a[MAXN],b[MAXN],Max[MAXN];
void NewNode(int &r,int father,ll k)  
{  
    r = ++tot;  
    pre[r] = father;  
    Max[r] = key[r] = sum[r] = k;;  
    ch[r][0] = ch[r][1] = 0;  
}  
void push_up(int r)  
{   
    sum[r] = sum[ch[r][0]] + sum[ch[r][1]] + key[r];  
    Max[r] = max(key[r],max(Max[ch[r][0]],Max[ch[r][1]]));
}  
void Rotate(int x,int kind)  
{  
    int y = pre[x];  
    ch[y][!kind] = ch[x][kind];  
    pre[ch[x][kind]] = y;  
    if(pre[y]) ch[pre[y]][ch[pre[y]][1] == y] = x;  
    pre[x] = pre[y];  
    ch[x][kind] = y;  
    pre[y] = x;  
    push_up(y);  
}  
void Splay(int r,int goal)  
{  
    while(pre[r] != goal)  
    {  
        if(pre[pre[r]] == goal) Rotate(r,ch[pre[r]][0] == r);  
        else  
        {  
            int y = pre[r];  
            int kind = ch[pre[y]][0] == y;  
            if(ch[y][kind] == r)  
            {  
                 Rotate(r,!kind);  
                 Rotate(r,kind);  
            }  
            else  
            {  
                Rotate(y,kind);  
                Rotate(r,kind);  
            }  
        }  
    }  
    push_up(r);  
    if(goal == 0) root = r;  
}
int Find(int r,ll val)  
{
	if(r == 0) return 0;
	if(Max[ch[r][0]] >= val) return Find(ch[r][0],val);
	if(key[r] >= val) return r;
	return Find(ch[r][1],val);
}
void Insert(int &r,ll val)
{
	if(r == 0)
	{
		NewNode(r,0,val);
		return;
	}
	if(val <= key[r]) 
	{
		if(!ch[r][0]) NewNode(ch[r][0],r,val);
	 	else Insert(ch[r][0],val);
	}
	else 
	{
		if(!ch[r][1]) NewNode(ch[r][1],r,val);
	 	else Insert(ch[r][1],val);
	}
	push_up(r);
}
void Init()  
{  
    root = tot = 0;  
    for(int i = 1;i <= n;i++) 
	{
		Insert(root,b[i]);
		if(i % 178 == 0) Splay(tot,0); 
	}
}  
void Delete_pos(int x)//删除节点  
{  
    Splay(x,0);  
    int tmp = ch[root][1];
	if(!tmp)
	{
		root = ch[root][0];
		pre[root] = 0;	
	}  
	else
	{
    	while(ch[tmp][0]) tmp = ch[tmp][0];   ;//找到根节点右子树最小元素(往左找)  
    	Splay(tmp,root);//将它移到根节点的右儿子  
    	ch[tmp][0] = ch[root][0];//将后继作为根节点,根节点删除。  
    	pre[ch[root][0]] = tmp;  
    	pre[tmp] = 0;  
    	root = tmp; //后继成为根节点  
    	push_up(root);
   }	
}  
void got()
{
	int tmp = root;
	while(ch[tmp][0]) tmp = ch[tmp][0]; 
    Splay(tmp,0);
	int ans = 1,temp;
	do
	{
		temp = Find(ch[root][1],key[root] + sum[ch[root][0]]);
		if(temp > 0) 
		{
			Splay(temp,0);
			if(key[root] >= sum[ch[root][0]]) ans++;
		}
	}while(temp > 0);
	printf("%d\n",ans);
}
int main()
{
	scanf("%d",&n);
	for(int i = 1;i <= n;i++) scanf("%lld",&b[i]); 
	Init();
	got();
	scanf("%d",&m);
	for(int i = 1;i <= m;i++)
	{
		int pos;ll val;
		scanf("%d%lld",&pos,&val);
		Delete_pos(Find(root,b[pos]));
		b[pos] = val;
		Insert(root,val);
		got();
		if(i % 280 == 0) Splay(tot,0);
	}	
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值