HDU6521Party(线段树)

                                                    Party

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


 

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

 

 

一、原题地址

点我传送

 

二、大致题意

有n个人,现在打算举办m场趴体。每一场趴体将会邀请编号[ l , r ] 的人,他们之间会互相认识。

现在每次趴体之后,询问新产生了多少互相认识的朋友。

 

三、大致思路

可以用一个数组maxx[ ]来记录当前第 i 个人的认识关系,如maxx[i] = j 则表示第 i 个人已经认识了[ j , i ]之间所有的人。即这个j表示的是 i 所有认识的人中编号最前端的一个人。

然后这个认识关系maxx[ ] 尝试用线段树维护。

但暴力的线段树一直到叶子节点去更新maxx值显然是超时的,所以提出了关键性的“剪枝”操作:

如果当前指向的人u的编号是大于当前查询的区间maxx值,则表示u在之前就已经被计算过了贡献,此时直接return。

 

这里看讨论区里的大佬是由图论来入手这道题分析复杂度的。个人的感觉是,对于每个询问我的确是下到了每个叶子节点去更新了maxx值,但是已经避免了大的区间上的重复查询,并且维护的是类似于一个不停指向前方的单向的东西。具体的复杂度仍在思考中。但是这种在线段树上做剪枝的操作真的很精妙呀!

 

四、代码

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<string>
#include<iostream>
#include<map>
#include<vector>
#include<set>
#include<queue>
using namespace std;
typedef unsigned long long ull;
typedef long long LL;
const int maxv = 4e6 + 4;


int n,m;
const int maxn = 500005 * 4;	
struct Tree
{
	int l, r;
	LL maxx;
};
Tree node[maxn];		

void PushUp(int i)
{
    node[i].maxx=max(node[i<<1].maxx,node[i<<1|1].maxx);
}

void build(int i, int l, int r)
{
	node[i].l = l; node[i].r = r;
	if (l == r)
	{
		node[i].maxx = l;
		return;
	}
	int mid = (l + r) / 2;
	build(i << 1, l, mid);
	build((i << 1) | 1, mid + 1, r);
	PushUp(i);
}

LL Query(int i, int l, int r,int u)
{
    if(u>=node[i].maxx)
    {
        return 0;
    }
    if(node[i].l==node[i].r)
    {
        LL ret=node[i].maxx-u;
        node[i].maxx=u;
        return ret;
    }
    int mid = (node[i].l + node[i].r) / 2;
    LL ret=0;
    if (r <= mid)
    {
        ret += Query(i << 1, l, r,u);
        PushUp(i);
        return ret;
    }
    else if (l > mid)
    {
        ret+=Query((i << 1) | 1, l, r,u);
        PushUp(i);
        return ret;
    }
    else
    {
        ret+= Query(i << 1, l, mid,u) + Query((i << 1) | 1, mid + 1, r,u);
        PushUp(i);
        return ret;
    }
}

int main()
{
    while(scanf("%d %d",&n,&m)!=EOF)
    {
        build(1,1,n);
        for(int i=1;i<=m;i++)
        {
            int u,v;
            scanf("%d %d",&u,&v);
            printf("%lld\n",Query(1,u,v,u));
        }
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值