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

BZOJ Zjoi2013 K大数查询

时间:2016-05-31 22:24:35      阅读:232      评论:0      收藏:0      [点我收藏+]

标签:

  刚学了整体二分,跟随神犇的步伐走向了这道题......

  神犇:这道题不是二分答案裸题吗? 我:......

  也许是我真的太弱了吧:

技术分享

  不过好歹是A了,讲一讲我的思路:

  首先,我们二分出一个答案mid,然后扫一遍当前区间内的询问,如果加入的数x>=mid,那么把这段区间的值都加1;这样就可以求出区间>=mid的数的个数了。

  然后,根据这些东西判断一下当前询问该丢到左边还是右边,递归处理就可以了。还有不要忘了询问的是区间第k大,所以对于丢到左边的询问要先把贡献给算进去。

  下面贴代码:

 1 #include<cstdio>
 2 #define maxn 50010
 3 
 4 using namespace std;
 5 typedef long long llg;
 6 
 7 struct data{
 8     int tp,l,r,k,id;
 9 }s[maxn],zl[maxn],zr[maxn];
10 int n,m,ans[maxn],tt;
11 llg c1[maxn],c2[maxn];
12 
13 int getint(){
14     int w=0,q=0;
15     char c=getchar();
16     while((c<0||c>9)&&c!=-) c=getchar();
17     if(c==-) q=1,c=getchar();
18     while(c>=0&&c<=9) w=w*10+c-0,c=getchar();
19     return q?-w:w;
20 }
21 
22 void add(int x,int y){for(int i=x;i<=n;i+=i&(-i)) c1[i]+=y,c2[i]+=(llg)x*y;}
23 llg sum(int x){
24     llg ans(0);
25     for(int i=x;i;i-=i&(-i)) ans+=(x+1)*c1[i]-c2[i];
26     return ans;
27 }
28 
29 void solve(int top,int end,int l,int r){
30     if(l==r){
31         for(int i=top;i<=end;i++)
32             ans[s[i].id]=l;
33         return;
34     }
35     int mid=l+r+1>>1,lo(0),ro(0);
36     bool ll(0),rr(0);llg x;
37     for(int i=top;i<=end;i++)
38         if(s[i].tp==1)
39             if(s[i].k>=mid) add(s[i].l,1),add(s[i].r+1,-1),zr[++ro]=s[i];
40             else zl[++lo]=s[i];
41         else{
42             x=sum(s[i].r)-sum(s[i].l-1);
43             if(x>=s[i].k) zr[++ro]=s[i],rr=1;
44             else s[i].k-=x,zl[++lo]=s[i],ll=1;
45         }
46     for(int i=top;i<=end;i++)
47         if(s[i].tp==1 && s[i].k>=mid) add(s[i].l,-1),add(s[i].r+1,1);
48     for(int i=1;i<=lo;i++) s[top+i-1]=zl[i];
49     for(int i=1;i<=ro;i++) s[top+i+lo-1]=zr[i];
50     if(ll) solve(top,top+lo-1,l,mid-1);
51     if(rr) solve(top+lo,end,mid,r);
52 }
53 
54 int main(){
55     n=getint();m=getint();
56     for(int i=1;i<=m;i++){
57         s[i].tp=getint();
58         s[i].l=getint(); s[i].r=getint();
59         s[i].k=getint();
60         if(s[i].tp==2) s[i].id=++tt;
61     }
62     solve(1,m,1,n);
63     for(int i=1;i<=tt;i++)
64         printf("%d\n",ans[i]);
65     return 0;
66 }

 

BZOJ Zjoi2013 K大数查询

标签:

原文地址:http://www.cnblogs.com/lcf-2000/p/5547552.html

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