P4848 崂山白花蛇草水

题面

• 平面是二维的,第 K 大是相对的。

• 单纯的 K- D 似乎并不能解决(反正我不会)。

• 第 K 大和二分是紧密相关的。

• 二分之后的判定就是一个二维数点问题。

• 所以我们可以线段树套 K-D tree 。

  1 #include<bits/stdc++.h>
  2 #define ls son[u][0]
  3 #define rs son[u][1]
  4 using namespace std;
  5 const double dat=0.8;
  6 const int N=1000000000;
  7 int n,m,cnt,tot,rt,ans;
  8 int opt,x[2],y[2],w,sum;
  9 int root[5000050];
 10 int ch[5000050][2];
 11 int val[5000050][2],siz[5000050];
 12 int L[5000050][2],R[5000050][2];
 13 int son[5000050][2];
 14 int t[5000050],top,K;
 15 bool cmp(int a,int b)
 16 {
 17     return val[a][K]<val[b][K];
 18 }
 19 void pushup(int u)
 20 {
 21     siz[u]=siz[ls]+siz[rs]+1;
 22     for(int i=0;i<=1;++i)
 23     {
 24         L[u][i]=min(val[u][i],min(L[ls][i],L[rs][i]));
 25         R[u][i]=max(val[u][i],max(R[ls][i],R[rs][i]));
 26     }
 27 }
 28 void dfs(int u)
 29 {
 30     t[++top]=u;
 31     if(ls)    dfs(ls);
 32     if(rs)    dfs(rs);
 33 }
 34 void calc_build(int &u,int l,int r,int k)
 35 {
 36     if(l>r)    
 37     {
 38         u=0;
 39         return ;
 40     }
 41     int mid=(l+r)>>1;    K=k;
 42     sort(t+l,t+r+1,cmp);    u=t[mid];
 43     calc_build(ls,l,mid-1,k^1);
 44     calc_build(rs,mid+1,r,k^1);
 45     pushup(u);
 46 }
 47 void calc_rebuild(int &u,int k)
 48 {
 49     t[top=1]=tot;dfs(u);
 50     calc_build(u,1,top,k);
 51 }
 52 void calc_insert(int &u,int k)
 53 {
 54     if(!u)
 55         u=tot;
 56     else if(val[tot][k]<val[u][k])
 57     {
 58         if(siz[ls]>siz[u]*dat)
 59         {
 60             calc_rebuild(u,k);
 61             return ;
 62         }
 63         else
 64             calc_insert(ls,k^1);
 65     }
 66     else
 67     {
 68         if(siz[rs]>siz[u]*dat)
 69         {
 70             calc_rebuild(u,k);
 71             return ;
 72         }
 73         else
 74             calc_insert(rs,k^1);
 75     }
 76     pushup(u);
 77     return ;
 78 }
 79 void calc_add(int &u,int l,int r,int pos)
 80 {
 81     if(!u)    u=++cnt;
 82     ++tot;
 83     val[tot][0]=x[0];
 84     val[tot][1]=x[1];
 85     calc_insert(root[u],0);
 86     if(l==r)    return ;
 87     int mid=(l+r)>>1;
 88     if(pos<=mid)    calc_add(ch[u][0],l,mid,pos);
 89     else    calc_add(ch[u][1],mid+1,r,pos);
 90 }
 91 bool flagALL;
 92 bool flagALO;
 93 bool flagBIT;
 94 void check(int u)
 95 {
 96     flagALL=true;    flagBIT=true;    flagALO=true;
 97     for(int i=0;i<=1;++i)
 98         if(L[u][i]<x[i]||R[u][i]>y[i])
 99         {
100             flagALL=false;
101             if(val[u][i]>y[i]||val[u][i]<x[i])
102             {
103                 flagALO=false;
104                 if(L[u][i]>y[i]||R[u][i]<x[i])
105                     flagBIT=false;
106             }
107         }
108 }
109 void ask(int u)
110 {
111     if(!u)    return ;
112     check(u);
113     if(flagALL)
114     {
115         sum+=siz[u];
116         return ;
117     }
118     if(flagALO)
119         sum+=1;
120     if(!flagBIT)
121         return ;
122     ask(ls);    ask(rs);
123 }
124 void calc_ask(int u,int l,int r)
125 {
126     if(l==r)
127     {
128         sum=0;    ask(root[u]);
129         ans=sum>=w? l:0;
130         return ;
131     }
132     int mid=(l+r)>>1;
133     sum=0;    ask(root[ch[u][1]]);
134     if(w>sum)
135     {
136         w-=sum;
137         calc_ask(ch[u][0],l,mid);
138     }
139     else
140         calc_ask(ch[u][1],mid+1,r);
141 }
142 int main()
143 {
144     L[0][0]=N;    L[0][1]=N;
145     R[0][0]=0;    R[0][1]=0;
146     scanf("%d%d",&n,&m);
147     while(m--)
148     {
149         scanf("%d%d%d",&opt,&x[0],&x[1]);
150         x[0]^=ans;    x[1]^=ans;
151         if(opt==1)
152         {
153             scanf("%d",&w);    w^=ans;
154             calc_add(rt,1,N,w);
155         }
156         else
157         {
158             scanf("%d%d%d",&y[0],&y[1],&w);
159             y[0]^=ans;    y[1]^=ans;    w^=ans;
160             calc_ask(rt,1,N);
161             if(!ans)    printf("NAIVE!ORZzyz.\n");
162             else        printf("%d\n",ans);
163         }
164     }
165     return 0;
166 }
View Code

转载于:https://www.cnblogs.com/wyher/p/10434413.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值