bzoj 3110 K大数查询

第一道整体二分,因为只需要知道每个询问区间中比mid大的数有多少个,就可以直接用线段树区间加,区间求和了。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #define int long long
  6 #define N 50005
  7 #define ls x*2,l,mid
  8 #define rs x*2+1,mid+1,r
  9 using namespace std;
 10 int n,m;
 11 struct node
 12 {
 13     int sign,x,y,c;
 14 }op[N];
 15 int q[N],ans[N];
 16 int a[N*8],lazy[N*8];
 17 void push_down(int x,int l,int mid,int r)
 18 {
 19     if(lazy[x]!=0)
 20     {
 21         lazy[x*2]+=lazy[x];
 22         lazy[x*2+1]+=lazy[x];
 23         a[x*2]+=lazy[x]*(mid-l+1);
 24         a[x*2+1]+=lazy[x]*(r-mid);
 25         lazy[x]=0;
 26     }
 27     return ;
 28 }
 29 int qur(int x,int l,int r,int ll,int rr)
 30 {
 31     if(l>=ll&&r<=rr)return a[x];
 32     int mid=(l+r)>>1;
 33     push_down(x,l,mid,r);
 34     if(rr<=mid)return qur(ls,ll,rr);
 35     if(ll>mid)return qur(rs,ll,rr);
 36     return qur(ls,ll,rr)+qur(rs,ll,rr);
 37 }
 38 void gai(int x,int l,int r,int ll,int rr,int d)
 39 {
 40     if(l>=ll&&r<=rr)
 41     {
 42         lazy[x]+=d;
 43         a[x]+=d*(r-l+1);
 44         return ;
 45     }
 46     int mid=(l+r)>>1;
 47     push_down(x,l,mid,r);
 48     if(ll<=mid)gai(ls,ll,rr,d);
 49     if(rr>mid)gai(rs,ll,rr,d);
 50     a[x]=a[x*2]+a[x*2+1];
 51 }
 52 int tmp[2][N];
 53 void solve(int L,int R,int l,int r)
 54 {
 55     if(L>R)return ;
 56     if(l==r)
 57     {
 58         for(int i=L;i<=R;i++)if(op[q[i]].sign==2)ans[q[i]]=l;
 59         return ;
 60     }
 61     int mid=(l+r)>>1;
 62     int cnt1=0,cnt2=0;
 63     for(int i=L;i<=R;i++)
 64     {
 65         if(op[q[i]].sign==1)
 66         {
 67             if(op[q[i]].c>mid)
 68             {
 69                 gai(1,1,n,op[q[i]].x,op[q[i]].y,1);
 70                 tmp[1][++cnt2]=q[i];
 71             }
 72             else tmp[0][++cnt1]=q[i];
 73         }
 74         else
 75         {
 76             int y=qur(1,1,n,op[q[i]].x,op[q[i]].y);
 77             if(y>=op[q[i]].c)
 78             {
 79                 tmp[1][++cnt2]=q[i];
 80             }
 81             else op[q[i]].c-=y,tmp[0][++cnt1]=q[i];
 82         }
 83     }
 84     for(int i=L;i<=R;i++)
 85     {
 86         if(op[q[i]].sign==1)
 87         {
 88             if(op[q[i]].c>mid)gai(1,1,n,op[q[i]].x,op[q[i]].y,-1);
 89         }
 90     }
 91     int l1=L+cnt1-1;
 92     for(int i=1;i<=cnt1;i++)q[L+i-1]=tmp[0][i];
 93     for(int i=1;i<=cnt2;i++)q[l1+i]=tmp[1][i];
 94     solve(L,l1,l,mid);solve(l1+1,R,mid+1,r);
 95 }
 96 signed main()
 97 {
 98     scanf("%lld%lld",&n,&m);
 99     for(int i=1;i<=m;i++)
100     {
101         scanf("%lld%lld%lld%lld",&op[i].sign,&op[i].x,&op[i].y,&op[i].c);
102         q[i]=i;
103     }
104     solve(1,m,1,n);
105     for(int i=1;i<=m;i++)
106     {
107         if(op[i].sign==2)printf("%lld\n",ans[i]);
108     }
109     return 0;
110 }
时间: 2025-01-20 09:45:11

bzoj 3110 K大数查询的相关文章

BZOJ 3110 K大数查询 树套树

题意:链接 方法:树套树(线段树套线段树) 题解:这题好神啊- -自己在做的时候一顿yy也没yy出用两个线段树来搞,其实我想的是类似二逼那道题那样,用线段树维护总区间,treap维护每个节点,不过这样的话,尼玛修改就是暴力有没有?而且查询的时候也是暴力啊有没有?绝壁不是这么做的啊! 上网上找了找题解综合了大家的思想自己也是懂了这题是咋回事了,也是跪了. 好不扯淡了,谈正经的,两个线段树是怎么搞得. 其实第一棵线段树是区间的线段树,而第二棵是维护值域的线段树,具体解析请看代码. #include

【cdq分治】【整体二分】bzoj 3110: [Zjoi2013] HYSBZ - 3110 K大数查询

题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3110 题意:有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c.如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少.注意是加入一个数,不是让这个数去求和. 题解:虽然是看cdq找到这题,但是感觉这个和平时做的三维偏序不大一样.这题其实是整体二分.就是首先,每次询问的答案应该是1,n之间的,然后

BZOJ Zjoi2013 K大数查询

刚学了整体二分,跟随神犇的步伐走向了这道题...... 神犇:这道题不是二分答案裸题吗? 我:...... 也许是我真的太弱了吧: 不过好歹是A了,讲一讲我的思路: 首先,我们二分出一个答案mid,然后扫一遍当前区间内的询问,如果加入的数x>=mid,那么把这段区间的值都加1:这样就可以求出区间>=mid的数的个数了. 然后,根据这些东西判断一下当前询问该丢到左边还是右边,递归处理就可以了.还有不要忘了询问的是区间第k大,所以对于丢到左边的询问要先把贡献给算进去. 下面贴代码: 1 #incl

树套树专题——bzoj 3110: [Zjoi2013] K大数查询 &amp; 3236 [Ahoi2013] 作业 题解

[原题1] 3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MB Submit: 978  Solved: 476 Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c 如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少. Input 第一行N,M 接下来M行,每行形如1 a b c或2 a b c Outpu

BZOJ 3110: [Zjoi2013]K大数查询( 树状数组套主席树 )

BIT+(可持久化)权值线段树, 用到了BIT的差分技巧. 时间复杂度O(Nlog^2(N)) ----------------------------------------------------------------------------------------- #include<cstdio> #include<cctype> #include<cstring> #include<algorithm> using namespace std;

BZOJ 3110: [Zjoi2013]K大数查询 [树套树]

3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 6050  Solved: 2007[Submit][Status][Discuss] Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少. Input 第一行N,M接下来M行,每行形如1 a

K大数查询 bzoj 3110

K大数查询 [问题描述] 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少. [输入格式] 第一行N,M 接下来M行,每行形如1 a b c或2 a b c [输出格式] 输出每个询问的结果 [样例输入] 2 5 1 1 2 1 1 1 2 2 2 1 1 2 2 1 1 1 2 1 2 3 [样例输出] 1 2 1 [样例说明] 第一个操作 后位置

3110: [Zjoi2013]K大数查询 树状数组套线段树

3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1384  Solved: 629[Submit][Status] Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少. Input 第一行N,M接下来M行,每行形如1 a b c或2 a b

K大数查询 HYSBZ - 3110

K大数查询 HYSBZ - 3110 本来是刷整体二分的,被这个sb题折腾了一下午,用cin就RE, 用scanf就过了=_= 收获就是偶然学到了树状数组区间修改区间查询的写法吧... 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 #define LL long long 6 const int maxn = 1e5 + 10; 7 cons