题解
- 题目简洁大方,好评!!!
- 这种题一般都是用树套树来做滴,题目大意:要求支持区间修改,区间查询第K大
- 考虑一下CDQ分治,先二分一个答案
- 我们就对于一下当前这一段的处理序列中,先依次处理,碰到询问就考虑是否可行
- 如果对于一个询问,发现当前的x之下查询的ans大于那个值,说明答案更小,所以要放到左边去递归处理
- 但是同时记得,把询问的值减掉查询出的ans,表示这一段肯定比它大,先减掉
- 至于查询的话,区间修改、区间查询,可以用树状数组就行了
代码
1 #include <cstdio>
2 #include <iostream>
3 #include <cstring>
4 #define ll long long
5 #define N 50010
6 using namespace std;
7 int n,m,ans[N];
8 ll sz1[N],sz2[N];
9 bool bz[N];
10 struct edge{ int d,x,y,c,op; }a[N],P[N],Q[N];
11 void add(int x,int y) { for (int r=x;x<=n;x+=x&-x) sz1[x]+=y,sz2[x]+=r*y; }
12 ll query(int x)
13 {
14 ll r=0;
15 for (int i=x;i;i-=i&-i) r+=(x+1)*sz1[i]-sz2[i];
16 return r;
17 }
18 void cdq(int L,int R,int l,int r)
19 {
20 if (L>R||l>r) return;
21 if (l==r)
22 {
23 for (int i=L;i<=R;i++) ans[a[i].d]=l;
24 return;
25 }
26 int mid=l+r+1>>1,num1=0,num2=0;ll x;
27 for (int i=L;i<=R;i++)
28 if (a[i].op==1)
29 {
30 if (a[i].c>=mid) add(a[i].x,1),add(a[i].y+1,-1),P[++num2]=a[i]; else Q[++num1]=a[i];
31 }
32 else
33 {
34 x=query(a[i].y)-query(a[i].x-1);
35 if (x>=a[i].c) P[++num2]=a[i]; else a[i].c-=x,Q[++num1]=a[i];
36 }
37 for (int i=L;i<=R;i++) if (a[i].op==1&&a[i].c>=mid) add(a[i].x,-1),add(a[i].y+1,1);
38 for (int i=1;i<=num1;i++) a[L+i-1]=Q[i];
39 for (int i=1;i<=num2;i++) a[L+num1+i-1]=P[i];
40 cdq(L,L+num1-1,l,mid-1),cdq(L+num1,R,mid,r);
41 }
42 int main()
43 {
44 scanf("%d%d",&n,&m);
45 for (int i=1;i<=m;i++)
46 {
47 scanf("%d%d%d%d",&a[i].op,&a[i].x,&a[i].y,&a[i].c),a[i].d=i;
48 if (a[i].op==2) bz[i]=1;
49 }
50 cdq(1,m,1,n);
51 for (int i=1;i<=m;i++) if (bz[i]) printf("%d
",ans[i]);
52 }