C78 二维线段树+动态开点 点修+区查 P3810 三维偏序(陌上花开)

视频链接:264 二维线段树+动态开点 点修+区查 P3810 三维偏序(陌上花开)_哔哩哔哩_bilibili

 

 

 

Luogu P3810 【模板】三维偏序(陌上花开)

// 二维线段树+动态开点 点修+区查 O(nlognlogn)
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

void read(int &x){ //快读
  x=0; char c=getchar();
  while(!isdigit(c))c=getchar();
  while(isdigit(c))x=x*10+c-'0',c=getchar();
}
#define N 100005
#define mid ((l+r)>>1)
int n,k,ans[N],last;
struct node{
  int a,b,c;
  bool operator<(node t){return a<t.a;}
}g[N]; //属性
int lsx[N*20],rsx[N*20],lsy[N*200],rsy[N*200];
int root,rt[N*20],d[N*200],totx,toty;

void changeY(int &u,int l,int r,int i){ //内修
  if(!u) u=++toty; //内树开点
  d[u]+=1;         //d[u]的经过次数
  if(l==r) return;
  if(g[i].c<=mid) changeY(lsy[u],l,mid,i);
  else changeY(rsy[u],mid+1,r,i);
}
void changeX(int &u,int l,int r,int i){ //外修
  if(!u) u=++totx;      //外树开点
  changeY(rt[u],1,k,i); //外层入内
  if(l==r) return;
  if(g[i].b<=mid) changeX(lsx[u],l,mid,i);
  else changeX(rsx[u],mid+1,r,i);
}

int queryY(int u,int l,int r,int y1,int y2,int i){ //内查
  if(y1<=l&&r<=y2) return d[u]; //内层覆盖即返回
  int res=0;
  if(y1<=mid) res+=queryY(lsy[u],l,mid,y1,y2,i);
  if(y2>=mid+1) res+=queryY(rsy[u],mid+1,r,y1,y2,i);
  return res;
}
int queryX(int u,int l,int r,int x1,int x2,int i){ //外查
  if(x1<=l&&r<=x2) 
    return queryY(rt[u],1,k,1,g[i].c,i); //外层覆盖即入内
  int res=0;
  if(x1<=mid) res+=queryX(lsx[u],l,mid,x1,x2,i);
  if(x2>=mid+1) res+=queryX(rsx[u],mid+1,r,x1,x2,i);
  return res;
}
int main(){
  read(n),read(k); //n元素数量,k最大属性值
  for(int i=1;i<=n;i++)
    read(g[i].a),read(g[i].b),read(g[i].c);
  sort(g+1,g+1+n); //按属性a升序
  last=1;
  for(int i=1;i<=n;i++){
    changeX(root,1,k,i); //点修
    if(g[i+1].a!=g[i].a){
      for(int j=last;j<=i;j++)
      ans[queryX(root,1,k,1,g[j].b,j)-1]++;
      last=i+1;
    }
  }
  for(int i=0;i<n;i++) printf("%d\n",ans[i]);
}

 

posted @ 2023-12-22 22:04  董晓  阅读(148)  评论(0编辑  收藏  举报