整體二分+樹狀陣列
這道題和某題類似:
整體二分,每次二分乙個值,因為是求第k大,比二分值大的在[l
,r] 區間+1,詢問就問這個區間的數,如果數量大於k,說明實際答案大於二分值,下放右區間,否則下放左區間,k減去詢問的值(因為後面不會再考慮mid~r的值),把區間加操作也按照權值兩邊下放,每次詢問完答案要撤銷之前的區間加操作
這題學了新姿勢:樹狀陣列區間修改+區間查詢
有篇介紹樹狀陣列的blog:
樹狀陣列區間修改的大致思想是將序列查分,區間加減就變成單點修改,詢問(l
,r) 區間和的時候求su
m(r)
−sum
(l−1
) 設原序列是
a ,查分序列是
b,得 su
m(i)
=a1+
a2+.
..ai
因為ai
=b1+
b2+.
..bi
所以su
m(i)
=b1∗
i+b2
∗(i−
1)+.
..+b
i∗1=
(i+1
)∗∑j
=1ib
j−∑j
=1ij
∗bj
然後這兩個東西都可以用樹狀陣列維護
code:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
#define inf 110000
using namespace std;
const int maxn = 110000;
struct node
node(int a1,int a2,ll a3,int a4,int a5)
}a[maxn],b[maxn],c[maxn]; int num;
ll s[maxn],si[maxn];
int ans[maxn];
int n,m;
int lowbit(int
x)void update(ll *tr,int
x,ll c)}
ll q(ll *tr,int x)return ret;}
void add(int l,int r,ll c)
ll query(int l,int r)
void solve(int lp,int rp,int
lc,int rc)
int mid=(lc+rc)>>1; int bn=0,cn=0;
for(int i=lp;i<=rp;i++)
else b[++bn]=a[i];
}else}}
for(int i=lp;i<=rp;i++)
if(a[i].s==0&&a[i].c>mid) add(a[i].l,a[i].r,-1);
for(int i=1;i<=bn;i++)a[lp+i-1]=b[i];
for(int i=1;i<=cn;i++)a[lp+bn+i-1]=c[i];
solve(lp,lp+bn-1,lc,mid);
solve(lp+bn,rp,mid+1,rc);
}int main()
else
}for(int i=1;i<=m;i++)ans[i]=-inf-1;
solve(1,num,-inf,inf);
for(int i=1;i<=m;i++)if(ans[i]!=-inf-1)printf("%d\n",ans[i]);
return
0;}
BZOJ 3110 Zjoi2013 K大數查詢
title bzoj 3110 zjoi2013 k大數查詢 categories bzoj date 2016 2 3 00 00 00 tags 樹套樹,整體二分 有n個位置,m個操作。操作有兩種,每次操作如果是1 a b c的形式表示在第a個位置到第b個位置,每個位置加入乙個數c 如果是2 a...
BZOJ 3110 Zjoi2013 K大數查詢
title bzoj 3110 zjoi2013 k大數查詢 categories bzoj date 2016 2 3 00 00 00 tags 樹套樹,整體二分 有n個位置,m個操作。操作有兩種,每次操作如果是1 a b c的形式表示在第a個位置到第b個位置,每個位置加入乙個數c 如果是2 a...
bzoj3110 Zjoi2013 K大數查詢
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 ...