HDU 6521 Party(吉司机线段树)

Party

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


 

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中山大学程序设计竞赛(重现赛)

题意:

给你n,m(n,m<=5e5),表示有编号1~n的人,m个区间

对于每个区间[l,r],表示编号为[l,r]的人之间任意两两配对的方法总数

要求对于每个区间,输出其任意两两配对的方法总数减去前面的区间已经有的选法总数

例如[2,5] 可以有 23 24 25 34 35 45      6种

再给你[4,6] 则只有 46 56 2种(45在上面出现过了)

思路:

把这题当图论来想。。。一段区间一定是连续的

令a[i]=k表示(k,i)(k+1,i)...,(i-1,i)已经被算入答案

初始化a[i]=i

对于每次给定的区间[ql,qr],如果max{a[ql],a[ql+1],...,a[qr]}中的最大值<=ql,那么表示区间i属于[ql,qr]中所有(ql,i)的方法总数已经计算过了

如果max{a[ql],a[ql+1],...,a[qr]}中的最大值>ql 那么就说明至少存在一个i(a[i]>ql)属于[ql,qr],使(ql,i)(ql+1,i),...,(a[i]-1,i)可以被算入答案,然后更新a[i]=ql

发现上述过程可以用一个线段树维护区间最大值。。。但是因为要计算答案,每次我们必须更新到底。。。(max{a[ql],a[ql+1],...,a[qr]}中的最大值<=ql,那么就可以直接return 0 了,否则继续往下更新)

在更新的同时统计答案

这就是传说中的吉司机线段树。。。

代码:

#include
#define ll long long
#define inf 0x3f3f3f3f
#define lson  (i<<1)
#define rson  (i<<1|1)
#define mid   ((l+r)>>1)
#define rep(i,a,b) for(register int i=(a);i<=(b);i++)
#define dep(i,a,b) for(register int i=(a);i>=(b);i--)
using namespace std;
const int maxn=500010;
int n,m,k;
struct node
{
    int ma,v;
}a[maxn<<2];
void build(int i,int l,int r)
{
    if(l==r)
    {
        a[i].ma=a[i].v=l;
        return ;
    }
    build(lson,l,mid);
    build(rson,mid+1,r);
    a[i].ma=max(a[lson].ma,a[rson].ma);
}
ll update(int i,int l,int r,int ql,int qr,int x)
{
    ll res=0;
    if(x>=a[i].ma) return res;
    if(l==r)
    {
        res+=a[i].v-x;
        //cout<mid) res+=update(rson,mid+1,r,max(mid+1,ql),qr,x);
    a[i].ma=max(a[lson].ma,a[rson].ma);
    return res;
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        build(1,1,n);
        rep(i,1,m)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            printf("%lld\n",update(1,1,n,x,y,x));
        }
    }
    return 0;
}

 

你可能感兴趣的:(数据结构:线段树/树状数组)