zoukankan      html  css  js  c++  java
  • 整体二分

    整体二分

    我们发现,题目满足二分性质, 但对于每一个询问二分又十分的慢,我们可以离线, 把答案一样的询问放在一起处理

    • 引入一道题

    P3527 [POI2011]MET-Meteors

    Solution

    我们需要区间加和单点查询, 考虑使用树状数组

    定义一个函数 $ f(l, r, L, R) $ 代表当前二分区间是 $ [l, r] $ , 答案在这个区间里的询问从 (L) 排到 (R)

    设 $ mid = (l + r) >> 1 $ 我们把 $ [l, mid] $ 这段操作加进去

    根据这次的操作,把询问分成两部分, 答案在 $ [l, mid] $ 内的和在 $ [mid + 1, r]$ 内的,递归直到 (l = r)

    时间复杂度???

    对于这道提来说, 类似线段树一样递归有 $ log m$ 层, 每层有 $ m $ 个操作,和 $ q $ 次询问

    总体复杂度为 $ O((m + n) long^2 m) $

    (code)

    #include<iostream>
    #include<cstdio>
    #include<vector>
    #include<cctype>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    using namespace std;
    #define rg register
    char ss[1 << 17], *A = ss, *B = ss;
    inline char gc(){ if(A == B) { B = (A = ss) + fread(ss, 1, 1 << 17, stdin); if(A ==B) return EOF; } return *A++; }
    inline int read(){
    	rg char ch = gc();
    	rg int x = 0, f = 0;
    	while(! isdigit(ch)) f |= (ch == '-'), ch = gc();
    	while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = gc();
    	return f ? -x : x;
    }
    const int N = 3e5 + 7;
    long long g[N << 1];
    int n, m, k;
    inline void modify(int x, int d){
    	for(int i = x; i; i ^= (i & -i)) g[i] += d;
    }
    inline long long ask(int x){
    	long long res = 0;
    	for(int i = x; i <= (m << 1); i += (i & -i)) res += g[i];
    	return res;
    }
    inline void add(int l, int r, int d){
    	modify(r, d);
    	modify(l - 1, -d);
    }
    int o[N], p[N], id[N], ans[N];
    int pre[N], pre_id[N];
    vector<int> have[N];
    struct node{
    	int l, r, d;
    	inline void init() { l = read(), r = read(), d = read(); }
    	inline void modify() { :: add(l, r, d); }
    	inline void in_modify() { :: add(l, r, -d); }
    }q[N];
    #define ll long long
    void solve(int l, int r, int L, int R){
    	if(L > R) return;
    	if(l == r) {
    		for(int i = L; i <= R; ++i) ans[id[i]] = l;
    		return;
    	}
    	int mid = (l + r) >> 1;
    	
    	int tl = L - 1, tr = R + 1;
    	for(int i = l; i <= mid; ++i) q[i].modify();
    	for(int i = L; i <= R; ++i){
    		ll tmp = 0;
    		for(auto &x : have[id[i]]){
    			tmp += ask(x) + ask(x + m);
    			if(tmp >= p[i]) break;
    		}
    		if(tmp >= p[i]) pre[++tl] = p[i], pre_id[tl] = id[i];
    		else pre[--tr] = p[i] - tmp, pre_id[tr] = id[i];
    	}
    	for(int i = l; i <= mid; ++i) q[i].in_modify();
    	memcpy(p + L, pre + L, 4 * (tl - L + 1));
    	memcpy(id + L, pre_id + L, 4 * (tl - L + 1));
    	memcpy(p + tl + 1, pre + tl + 1, 4 * (R - tl));
    	memcpy(id + tl + 1, pre_id + tl + 1, 4 * (R - tl));
    	//for(int i = L; i <= tl; ++i) p[i] = pre[i], id[i] = pre_id[i];
    	//for(int i = R; i >= tr; --i) p[i] = pre[i], id[i] = pre_id[i];
    	solve(l, mid, L, tl); solve(mid + 1, r, tr, R);
    }
    signed main(){
    	n = read(), m = read();
    	for(int i = 1; i <= m; ++i) have[read()].push_back(i);
    	for(int i = 1; i <= n; ++i) p[i] = read(), id[i] = i;
    	k = read();
    	for(int i = 1; i <= k; ++i) q[i].init();
    	for(int i = 1; i <= k; ++i) if(q[i].r < q[i].l) q[i].r += m;
    	q[k + 1].l = 1, q[k + 1].r = 1, q[k + 1].d = 0;
    	solve(1, k + 1, 1, n);
    	for(int i = 1; i <= n; ++i) (ans[i] == k + 1) ? puts("NIE") : printf("%d
    ", ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    PLSQL游标
    SqlHelper助手
    机房重构前奏——三层转七层
    应用运筹管理经济
    C++——宏观把控
    操作系统——宏观把控
    .NET总结一
    深复制与浅复制
    设计模式之结构型
    设计模式之一对多
  • 原文地址:https://www.cnblogs.com/XiaoVsun/p/13054254.html
Copyright © 2011-2022 走看看