码迷,mamicode.com
首页 > 其他好文 > 详细

HDU - 5412 CRB and Queries (整体二分)

时间:2019-01-18 10:55:22      阅读:191      评论:0      收藏:0      [点我收藏+]

标签:and   ==   class   线段   高效   targe   方便   平衡   --   

题目链接

动态区间第k小,但是这道题的话用主席树+树状数组套线段树的空间复杂度是O(nlog2n)会爆掉。

另一种替代的方法是用树状数组套平衡树,空间复杂度降到了O(nlogn),但我感觉平衡树是个挺恶心的东西,而且时间复杂度是O(nlog3n),比主席树还多了个logn。

最高效的方法是用一个叫整体二分的东西算法,它的基本思想是这样的:

假设当前所有查询的答案范围都在[l,r]之间,设mid=(l+r)/2,那么我们只处理所有修改后的值在[l,mid]中的修改操作,把不需要执行的修改操作全部扔到后半区间,那么对于每个询问操作都可以知道它的答案是在[l,mid]之间还是(mid+1,r]之间,这样就把所有的询问划分到了两个独立的区间,然后递归处理即可。本质上是将原序列转化成01序列,这样处理起来就方便多了。与CDQ分治较为类似,是个很神奇的算法。

空间复杂度O(n),时间复杂度O(nlog2n)

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 const int inf=0x3f3f3f3f;
 5 const int N=1e5+10;
 6 struct QR {
 7     int f,l,r,k,u,x,dx;
 8 } qr[N<<2];
 9 
10 int a[N],c[N],b[N<<2],lq[N<<2],rq[N<<2],nq,tot,ans[N],n,m;
11 int lowbit(int x) {return x&-x;}
12 void add(int u,int x) {
13     for(; u<=n; u+=lowbit(u))c[u]+=x;
14 }
15 int query(int u) {
16     int ret=0;
17     for(; u; u-=lowbit(u))ret+=c[u];
18     return ret;
19 }
20 
21 void solve(int l,int r,int L,int R) {
22     if(L>R)return;
23     if(l==r) {
24         for(int i=L; i<=R; ++i)if(qr[b[i]].f)ans[qr[b[i]].u]=l;
25         return;
26     }
27     int nl=0,nr=0,mid=(l+r)>>1;
28     for(int i=L; i<=R; ++i) {
29         if(!qr[b[i]].f) {
30             if(qr[b[i]].x<=mid)add(qr[b[i]].u,qr[b[i]].dx),lq[nl++]=b[i];
31             else rq[nr++]=b[i];
32         } else {
33             int t=query(qr[b[i]].r)-query(qr[b[i]].l-1);
34             if(qr[b[i]].k<=t)lq[nl++]=b[i];
35             else qr[b[i]].k-=t,rq[nr++]=b[i];
36         }
37     }
38     for(int i=0; i<nl; ++i)if(!qr[lq[i]].f)add(qr[lq[i]].u,-qr[lq[i]].dx);
39     for(int i=0; i<nl; ++i)b[L+i]=lq[i];
40     for(int i=0; i<nr; ++i)b[L+nl+i]=rq[i];
41     solve(l,mid,L,L+nl-1);
42     solve(mid+1,r,L+nl,R);
43 }
44 
45 int main() {
46     while(scanf("%d",&n)==1) {
47         nq=tot=0;
48         memset(c,0,sizeof c);
49         int maxn=0;
50         for(int i=1; i<=n; ++i) {
51             scanf("%d",&a[i]);
52             maxn=max(maxn,a[i]);
53             qr[nq++]=(QR) {0,0,0,0,i,a[i],1};
54         }
55         scanf("%d",&m);
56         while(m--) {
57             int f;
58             scanf("%d",&f);
59             if(f==1) {
60                 int u,x;
61                 scanf("%d%d",&u,&x);
62                 qr[nq++]=(QR) {0,0,0,0,u,a[u],-1};
63                 qr[nq++]=(QR) {0,0,0,0,u,a[u]=x,1};
64                 maxn=max(maxn,a[u]);
65             } else {
66                 int l,r,k;
67                 scanf("%d%d%d",&l,&r,&k);
68                 qr[nq++]=(QR) {1,l,r,k,tot++,0,0};
69             }
70         }
71         for(int i=0; i<nq; ++i)b[i]=i;
72         solve(0,maxn,0,nq-1);
73         for(int i=0; i<tot; ++i)printf("%d\n",ans[i]);
74     }
75     return 0;
76 }

 

HDU - 5412 CRB and Queries (整体二分)

标签:and   ==   class   线段   高效   targe   方便   平衡   --   

原文地址:https://www.cnblogs.com/asdfsag/p/10286317.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!