BZOJ3262 陌上花开

以前的树套树第一题,好像也是除了二维线段树和二维bit的唯一一道树套树。

三维偏序是很裸的cdq,注意排序时,一是cdq里面sort的时候不能说按x为第一关键字就只比较第一关键字,这可能导致y1处的修改在y2的询问后面(y1<=y2),第二个是用重载的 < 比cmp快很多很多,把cdq里面的cmp去了之后快了1s。

//QWsin 
#include<cmath> 
#include<cstdio> 
#include<cstring> 
#include<iostream> 
#include<algorithm> 
using namespace std; 
const int maxn=100000+10; 
const int maxk=200000+10; 

inline int read() 
{ 
    int ret=0;char ch=getchar();     
    while(ch<'0'||ch>'9') ch=getchar(); 
    for(;ch>='0'&&ch<='9';ch=getchar()) ret=ret*10+ch-'0'; 
    return ret; 
} 

int n,k; 
struct Node{ 
    int x,y,z,t,id; 
    inline void input(int i){id=i;x=read();y=read();z=read();}   
    bool operator != (const Node &rhs)const{ 
        return  x!=rhs.x||y!=rhs.y||z!=rhs.z; 
    } 
    inline bool operator < (const Node &rhs)const{ 
        if(y!=rhs.y) return y<rhs.y; 
        if(x!=rhs.x) return x<rhs.x; 
        return z<rhs.z; 
    } 
}x[maxn],t[maxn]; 

int ans[maxn],cnt[maxn],num[maxn]; 

int cmp1(Node a,Node b){ 
    if(a.x!=b.x) return a.x<b.x; 
    if(a.y!=b.y) return a.y<b.y; 
    return a.z<b.z; 
} 
int id[maxn]; 

int C[maxk]; 

#define lowbit(i) ((i)&-(i)) 
inline void updata(int pos,int val){ 
    for(int i=pos;i<=k;i+=lowbit(i)) C[i]+=val;   
} 
inline int query(int pos){ 
    int ret=0; 
    for(int i=pos;i;i-=lowbit(i)) ret+=C[i]; 
    return ret;  
} 

void solve(int l,int r) 
{ 
    if(l>=r) return ; 
    int mid=(l+r)>>1; 

    solve(l,mid); 
    solve(mid+1,r); 
    for(int i=l;i<=mid;++i) x[i].t=0; 
    for(int i=mid+1;i<=r;++i) x[i].t=1; 

    for(int i=l;i<=r;++i) t[i]=x[i]; 

    sort(t+l,t+r+1); 

    for(int i=l;i<=r;++i) 
        if(!t[i].t) updata(t[i].z,num[t[i].id]); 
        else ans[t[i].id]+=query(t[i].z); 

    for(int i=l;i<=r;++i)  
        if(!x[i].t) updata(x[i].z,-num[x[i].id]); 
} 

char s[20];int p; 
inline void output(int x){ 
    if(!x) {putchar('0');} 
    else{ 
        for(p=0;x;x/=10) s[++p]=x%10+'0'; 
        for(int i=p;i>=1;--i) putchar(s[i]); 
    } 
    putchar('\n'); 
} 

int main() 
{ 
    cin>>n>>k; 
    for(int i=1;i<=n;++i) t[i].input(i); 

    sort(t+1,t+n+1,cmp1); 

    int p=0; 
    for(int i=1;i<=n;++i)  
    { 
        if(i==1||t[i]!=t[i-1]) x[++p]=t[i],num[p]=1,x[p].id=p; 
        else ++num[p]; 
    } 
    solve(1,p); 

    for(int i=1;i<=n;++i) cnt[ans[i]+num[i]-1]+=num[i]; 

    for(int i=0;i<n;++i) output(cnt[i]); 
    return 0; 
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值