3110: [Zjoi2013]K大数查询

3110: [Zjoi2013]K大数查询

https://lydsy.com/JudgeOnline/problem.php?id=3110

分析:

  整体二分+线段树。

  两种操作:区间加入一个数,区间询问第k大值。

  如果只有一种操作,我们可以二分答案x,然后把大于x的都加入到线段树中去(区间[l,r]整体+1),然后查询这次询问的区间有多少数(区间[l,r]求和)。

  多种操作的话整体二分就行了,注意到有时间顺序,所以可以按照时间顺序加入和查询。

  注意一下要开longlong。

代码:

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<cmath>
 6 #include<cctype>
 7 #include<set>
 8 #include<queue>
 9 #include<vector>
10 #include<map>
11 #define Root 1, n, 1
12 #define lson l, mid, rt << 1
13 #define rson mid + 1, r, rt << 1 | 1
14 using namespace std;
15 typedef long long LL;
16 
17 inline int read() {
18     int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
19     for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
20 }
21 
22 const int N = 50005;
23 
24 int ans[N], n, m;
25 struct Que{
26     int ty, l, r, v, id;
27     bool operator < (const Que &A) const {
28         return id < A.id;
29     }
30 }A[N], tl[N], tr[N];
31 struct SegmentTree{
32     LL sum[N << 2], tag[N << 2];
33     void pushup(int rt) { sum[rt] = sum[rt << 1] + sum[rt << 1 | 1]; }
34     void pushdown(int rt,int len) {
35         sum[rt << 1] += 1ll * (len - len / 2) * tag[rt];
36         sum[rt << 1 | 1] += 1ll * (len / 2) * tag[rt];
37         tag[rt << 1] += tag[rt];
38         tag[rt << 1 | 1] += tag[rt];
39         tag[rt] = 0;
40     }
41     void update(int l,int r,int rt,int L,int R,int v) {
42         if (L <= l && r <= R) {
43             tag[rt] += v, sum[rt] += (r - l + 1) * v; return ;
44         }
45         if (tag[rt]) pushdown(rt, r - l + 1);
46         int mid = (l + r) >> 1;
47         if (L <= mid) update(lson, L, R, v);
48         if (R > mid) update(rson, L, R, v);
49         pushup(rt);
50     }
51     LL query(int l,int r,int rt,int L,int R) {
52         if (L <= l && r <= R) return sum[rt]; 
53         if (tag[rt]) pushdown(rt, r - l + 1);
54         int mid = (l + r) >> 1; LL res = 0;
55         if (L <= mid) res += query(lson, L, R);
56         if (R > mid) res += query(rson, L, R);
57         return res;
58     }
59 }T;
60 
61 void solve(int l,int r,int Head,int Tail) {
62     if (Head > Tail) return ;
63     if (l == r) {
64         for (int i = Head; i <= Tail; ++i) 
65             if (A[i].ty == 2) ans[A[i].id] = l;
66         return ;
67     }
68     int mid = (l + r + 1) >> 1, cl = 0, cr = 0;
69     for (int i = Head; i <= Tail; ++i) {
70         if (A[i].ty == 1) {
71             if (A[i].v >= mid) T.update(Root, A[i].l, A[i].r, 1), tr[++cr] = A[i];
72             else tl[++cl] = A[i];
73         }
74         else {
75             LL t = T.query(Root, A[i].l, A[i].r);
76             if (t >= A[i].v) tr[++cr] = A[i];
77             else A[i].v -= t, tl[++cl] = A[i];
78         }
79     }
80     for (int i = Head; i <= Tail; ++i) if (A[i].ty == 1 && A[i].v >= mid) T.update(Root, A[i].l, A[i].r, -1);
81     for (int i = 1; i <= cl; ++i) A[i + Head - 1] = tl[i];
82     for (int i = 1; i <= cr; ++i) A[i + Head + cl - 1] = tr[i]; 
83     solve(l, mid - 1, Head, Head + cl - 1);
84     solve(mid, r, Head + cl, Tail);
85 }
86 int main() {
87     n = read(), m = read(); int Q = 0;
88     for (int i = 1; i <= m; ++i) {
89         A[i].ty = read(), A[i].l = read(), A[i].r = read(), A[i].v = read(), A[i].id = 0;
90         if (A[i].ty == 2) A[i].id = ++Q;
91     }
92     solve(0, n, 1, m);
93     for (int i = 1; i <= Q; ++i) printf("%d\n",ans[i]);
94     return 0;
95 }

 

posted @ 2018-12-07 11:12  MJT12044  阅读(181)  评论(0编辑  收藏  举报