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
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;
}