zoukankan      html  css  js  c++  java
  • P3332 [ZJOI2013]K大数查询

    (color{#0066ff}{ 题目描述 })

    有N个位置,M个操作。操作有两种,每次操作如果是:

    • 1 a b c:表示在第a个位置到第b个位置,每个位置加上一个数c
    • 2 a b c:表示询问从第a个位置到第b个位置,第C大的数是多少。

    (color{#0066ff}{输入格式})

    第一行N,M接下来M行,每行形如1 a b c或2 a b c

    (color{#0066ff}{输出格式})

    输出每个询问的结果

    (color{#0066ff}{输入样例})

    2 5
    1 1 2 1
    1 1 2 2
    2 1 1 2
    2 1 1 1
    2 1 2 3
    

    (color{#0066ff}{输出样例})

    1
    2
    1
    

    (color{#0066ff}{数据范围与提示})

    第一个操作后位置 1 的数只有 1 , 位置 2 的数也只有 1 。
    第二个操作 后位置 1 的数有 1 、 2 ,位置 2 的数也有 1 、 2 。
    第三次询问 位置 1 到位置 1 第 2 大的数是1 。
    第四次询问 位置 1 到位置 1 第 1 大的数是 2 。 第五次询问 位置 1 到位置 2 第 3大的数是 1 。

    N,M<=50000,N,M<=50000
    a<=b<=N
    1操作中abs(c)<=N
    2操作中c<=long long

    (color{#0066ff}{题解})

    这里是区间加上一个数,可以用树套树做qwq

    个人认为整体二分比较好写,而且用一个线段树维护区间加,区间求和就行了

    注意开long long!!!!

    // luogu-judger-enable-o2
    #include<bits/stdc++.h>
    #define LL long long
    LL in() {
    	char ch; LL x = 0, f = 1;
    	while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
    	for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
    	return x * f;
    }
    struct Tree {
    protected:
    	struct node {
    		node *ch[2];
    		int l, r;
    		LL val, tag;
    		node(int l = 0, int r = 0, LL val = 0, LL tag = 0): l(l), r(r), val(val), tag(tag) { ch[0] = ch[1] = NULL; }
    		void upd() { val = ch[0]->val + ch[1]->val; }
    		void trn(LL k) { val += 1LL * (r - l + 1) * k, tag += k; }
    		int mid() { return (l + r) >> 1; }
    		void dwn() {
    			if(!tag) return;
    			ch[0]->trn(tag), ch[1]->trn(tag), 
    			tag = 0;
    		}
    	}*root;
    	void build(node *&o, int l, int r) {
    		o = new node(l, r, 0, 0);
    		if(l == r) return;
    		int mid = (l + r) >> 1;
    		build(o->ch[0], l, mid);
    		build(o->ch[1], mid + 1, r);
    	}
    	void lazy(node *o, int l, int r, LL k) {
    		if(l <= o->l && o->r <= r) return o->trn(k);
    		o->dwn();
    		if(l <= o->mid()) lazy(o->ch[0], l, r, k);
    		if(r > o->mid()) lazy(o->ch[1], l, r, k);
    		o->upd();
    	}
    	LL query(node *o, int l, int r) {
    		if(l <= o->l && o->r <= r) return o->val;
    		o->dwn();
    		LL ans = 0;
    		if(l <= o->mid()) ans += query(o->ch[0], l, r);
    		if(r > o->mid()) ans += query(o->ch[1], l, r);
    		return ans;
    	}
    public:
    	void build(int l, int r) { build(root, l, r); }
    	void lazy(int l, int r, LL k) { lazy(root, l, r, k); }
    	LL query(int l, int r) { return query(root, l, r); }
    }s;
    const int maxn = 1e5 + 10;
    struct node {
    	int tp, l, r, id;
    	LL k;
    	node(int tp = 0, int l = 0, int r = 0, int id = 0, LL k = 0): tp(tp), l(l), r(r), id(id), k(k) {}
    }q[maxn], ql[maxn], qr[maxn];
    int n, m, num, id[maxn];
    LL ans[maxn];
    void work(LL l, LL r, int nl, int nr) {
    	if(l > r || nl > nr) return;
    	if(l == r) {
    		for(int i = nl; i <= nr; i++) if(q[i].tp == 2) ans[q[i].id] = l;
    		return;
    	}
    	LL mid = (l + r) >> 1, cntl = 0, cntr = 0;
    	for(int i = nl; i <= nr; i++) {
    		if(q[i].tp == 2) {
    			LL k = s.query(q[i].l, q[i].r);
    			if(q[i].k <= k) qr[++cntr] = q[i];  //这里应该放右边!!
    			else q[i].k -= k, ql[++cntl] = q[i];  
    		}
    		else {
    			if(q[i].k <= mid) ql[++cntl] = q[i];
    			else qr[++cntr] = q[i], s.lazy(q[i].l, q[i].r, 1);
    		}
    	}
    	for(int i = nl; i <= nr; i++) if(q[i].tp == 1 && q[i].k > mid) s.lazy(q[i].l, q[i].r, -1);
    	for(int i = 1; i <= cntl; i++) q[nl + i - 1] = ql[i];
    	for(int i = 1; i <= cntr; i++) q[nl + cntl + i - 1] = qr[i];
    	work(l, mid, nl, nl + cntl - 1), work(mid + 1, r, nl + cntl, nr);
    }
    int main() {
    	n = in(), m = in();
    	s.build(1, n);
    	int p, x, y;
    	LL max = 0, z;
    	for(int i = 1; i <= m; i++) {
    		p = in(), x = in(), y = in(), z = in();
    		q[i] = node(p, x, y, i, z);
    		max = std::max(max, z);
    		if(p == 2) id[++num] = i;
    	}
    	work(-max, max, 1, m);
    	for(int i = 1; i <= num; i++) printf("%lld
    ", ans[id[i]]);
    	return 0;
    }
    
  • 相关阅读:
    文件查找和压缩
    shell脚本编程基础
    [模板]数据生成与对拍
    Codeforces Round #746 (Div. 2)
    Codeforces Round #712 (Div. 2)
    Codeforces Round #715 (Div. 2)
    Codeforces Round #752 (Div. 2)
    提高模拟赛Day8T3树上跑步
    提高模拟赛Day8T2最大匹配
    提高模拟赛Day8T1求中位数
  • 原文地址:https://www.cnblogs.com/olinr/p/10408614.html
Copyright © 2011-2022 走看看