2019中山大学程序设计竞赛 K. Party(吉司机线段树)

Party

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 235    Accepted Submission(s): 87


 

Problem Description

n person have just entered a company, and Xiaoxun, as a supervisor, gives each of them a number from 1 to n that is not repeated. 

In order to let them to get to know each other better, they would have a party every day, and there was a limit on the number of people at each party. Xiaoxun didn't want to find a way to find people randomly. So every time he had a party, he would only invite people with numbers in a certain interval to play. 

The people who come to the party will get to know each other, and Xiaoxun wants to know how effective each party is. The effect is evaluated as the number of pairs of people at this party who did not appear at the same previous party.

 

 

Input

There are mutiple test cases.

Each case starts with a line containing two integers n,m(n≤5×105,m≤5×105)which represent the number of people and the number of parties. And this is followed by m lines each containing two integers l,r(1≤l≤r≤n) which mean the interval, and only the people whose number in the interval can take part in this party.

 

 

Output

For each case you should print m lines.

Each line containing a integer mean the effect of this party.

 

 

Sample Input

 

5 4 1 2 4 5 1 4 2 5

 

 

Sample Output

 

1 1 5 2

Hint

explaination of sample: The first party: 1-2 The second party: 4-5 The third party: 1-3 1-4 2-3 2-4 3-4 The fourth party: 2-5 3-5

 

 

Source

2019中山大学程序设计竞赛(重现赛)

 

 

Recommend

liuyiding   |   We have carefully selected several similar problems for you:  6521 6520 6519 6518 6517 

 

题意:

n个人,开m次派对,每次派对每对人会相互认识对方。对于每一次派对,我们要求出新认识的pair的数量

分析:

思路参考:学长博客:https://blog.csdn.net/LSD20164388/article/details/89413657

这题关键的一个性质就是认识的人是一段连续的区间。因为是算数量,所以可以把相互认识当作有向边,每个边当作从小连向大的有向边即可,即下面初始a[i]=i,最大也只能是i。

我们设a[i]=k,表示(k,i),(k+1,i),.....(i-1,i)已经被计算过答案,不需要添加。

假设我们查询的区间为(l,r),

如果l>=max(a[l].......a[r]),不能算作答案了。

如果l<max(a[l].......a[r]),则至少存在一点i,可以找到新关系(l,i),(l+1,i)。。。。(i-1,i),这里需要更新查询到叶子节点,所以我们需要一个dat来记录这个人认识到他前面第几个人了,ans+=a[i].dat-l,a[i].dat=l。

综上,该线段树查询功能为:如果该区间的某一个值大于或小于最大值,需要暴力的修改这个位置的值,需要该线段树。

 

#include<bits/stdc++.h>
using namespace std;
const int N=500010;
#define ll long long
int n,m;
 
struct node  //线段树
{
    int l,r;
    ll dat,ma;
}tree[N*4];
 

void PushUp(int x)   //线段树维护结点信息
{
	tree[x].ma=max(tree[x<<1].ma,tree[x<<1|1].ma);
}
void build(int x,int l,int r)  //线段树建树
{
	tree[x].l=l;
	tree[x].r=r;
    if (l==r)   //叶子节点
    {
    	tree[x].ma=tree[x].dat=l;
        return;
    }
    int mid=(l+r)>>1;
    build(x<<1,l,mid);
    build(x<<1|1,mid+1,r);
	PushUp(x);
}  
 
ll query(int x,int l,int r,int val)  //线段树区间查询
{  
    
    if(val>=tree[x].ma) return 0;
    ll ans=0;
    if(tree[x].l==tree[x].r)
	{
		 ans+=tree[x].dat-val;
		 tree[x].ma=tree[x].dat=val;
		 return ans;
	}
	int mid=(tree[x].l+tree[x].r)>>1;
    if (l<=tree[x].l&&r>=tree[x].r) 
    {
    	ans+=query(x<<1,l,mid,val);
    	ans+=query(x<<1|1,mid+1,r,val);
		PushUp(x);
    	return ans; 
    }
    if (l<=mid) ans+=query(x<<1,l,min(r,mid),val);
    if (r>mid)  ans+=query(x<<1|1,max(l,mid+1),r,val); 
    PushUp(x);
    return  ans;
}
int main()
{
     int n,m;
    while(~scanf("%d%d",&n,&m)){
        build(1,1,n);
        for(int i=1;i<=m;++i){
            int l,r;
            scanf("%d%d",&l,&r);
            ll ans=query(1,l,r,l);
            printf("%lld\n",ans);
        }
    }

    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值