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 ",ans[i]); 94 return 0; 95 }