【POJ2481】cows 线段树

本文介绍了一种解决二维偏序问题的方法,通过自定义排序和线段树来统计每头牛相对于其他牛的强度,适用于数量级不超过10^5的数据规模。

题目描述

  农民约翰的奶牛们已经发现,越来越多的草沿山脊(看成是一个数轴)长的特别好。约翰有N头牛(编号从1到N)。每头奶牛都特别喜欢吃一定范围内的草(可能重叠)。这个范围可以看成是一个闭区间[S,E]。
  例如两头牛cowi和cowj,它们喜欢吃草的范围分别为[Si,Ei]和[Sj,Ej]。如果Si<=Sj,Ej <= Ei且Ei-Si > Ej-Sj,我们就是cowi比cowj强壮。对于每头牛来说,有多少牛是比她强呢?农民约翰需要你的帮助!

题目大意

二维偏序(不知道是不是这个意思)。

数据范围

(1<=N<=10^5)(0 <= S < E <= 10^5)

样例输入

3
1 2
0 3
3 4
0

样例输出

1 0 0

解题思路

  按s为第一关键字排序e为第二关键字排序(s相同时e大的排前面),对于i,就是统计≤Si且≥Ei再减去与SiEi相同的个数。不想写树状数组233。

代码

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
using namespace std;
namespace IStream{const int LLL=1<<15;char buffer[LLL],*SSS,*TTT;char Get_Char(){if(SSS==TTT){TTT=(SSS=buffer)+fread(buffer,1,LLL,stdin);if(SSS==TTT) return EOF;}return *SSS++;}int Getint(){char c;int re=0,f=1;for(c=Get_Char();c<'0'||c>'9';c=Get_Char())if(c=='-')f=-1;while(c>='0'&&c<='9')re=(re<<1)+(re<<3)+(c-'0'),c=Get_Char();return re*f;}}class OStream{private:static const int LLL=1<<15;char staack[21];int topp;char buffer[LLL],*SSS;public:OStream(){SSS=buffer;}void Putint(int x,int flag){bool fl=false;if(flag==1) staack[++topp]=' ';if(flag==2) staack[++topp]='\n';if(x<0) x=-x,fl=true;if(!x) staack[++topp]='0';while(x)staack[++topp]=x%10+'0',x/=10;if(fl)staack[++topp]='-';while(topp){if(SSS==buffer+LLL-1){fwrite(buffer,1,SSS-buffer,stdout);SSS=buffer;}*SSS++=staack[topp--];}}~OStream(){fwrite(buffer,1,SSS-buffer,stdout);*SSS=0;}}os;
#ifndef ONLINE_JUDGE
inline int Getint(){int x=0,f=1;char ch=getchar();while('0'>ch||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while('0'<=ch&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}
#else
using namespace IStream;
#endif
struct node{
    int s,e,Ans,pos;
}w[100005];
bool cmp1(node a,node b){return a.s<b.s||(a.s==b.s&&a.e>b.e);}
bool cmp2(node a,node b){return a.pos<b.pos;}
struct Seg{
    int L,r,Sum;
}Tree[400040];
void Build(int v,int L,int r){
    Tree[v]=(Seg){L,r,0};
    if(L==r)return;
    Build(2*v,L,(L+r)/2);
    Build(2*v+1,(L+r)/2+1,r);
}
int Ask(int v,int vl){
    if(Tree[v].r<vl)return 0;
    if(vl<=Tree[v].L)return Tree[v].Sum;
    return Ask(2*v,vl)+Ask(2*v+1,vl);
}
void Insert(int v,int vl){
    if(vl<Tree[v].L||Tree[v].r<vl)return;
    Tree[v].Sum++;
    Insert(v*2,vl);
    Insert(v*2+1,vl);
}
int main(){
    while(1){
        int n=Getint(),tot=0;
        if(!n)break;
        for(int i=1;i<=n;i++)w[i]=(node){Getint()+1,Getint()+1,0,i};
        sort(w+1,w+n+1,cmp1);
        Build(1,1,100004);
        for(int i=1;i<=n;i++){
            w[i].Ans=Ask(1,w[i].e)-(w[i].s==w[i-1].s&&w[i].e==w[i-1].e?++tot:tot=0);
            Insert(1,w[i].e);
        }
        sort(w+1,w+n+1,cmp2);
        for(int i=1;i<=n;i++)cout<<w[i].Ans<<" ";cout<<"\n";
    }
    return 0;
}

转载于:https://www.cnblogs.com/Cedric341561/p/6811028.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值