zoukankan      html  css  js  c++  java
  • Solution -「洛谷 P4688」「YunoOI 2016」掉进兔子洞

    Description

    (Link)[https://www.luogu.com.cn/problem/P4688].

    每次询问三个区间,把三个区间中同时出现的数一个一个删掉,问最后三个区间剩下的数的个数和,询问独立。

    Solution

    读完题,我们可以发现每轮询问的答案是这个东西:

    [sum_{i=1}^{3}(r_{i}-l_{i}+1)-P imes 3 ]

    其中,(P) 表示三个区间里面的公共颜色数量。

    前面那个 (sum) 里面的东西很好维护,我们主要来讲后面一部分的维护方法。

    首先初始序列的 (a_{i}) 是一定要离散化一遍的。

    那么我们如何表示出出现的最少次数呢?

    如果这是一个二进制串的话,我们可以发现这就是一个 (operatorname{bit\_and}) 的操作。

    对于每个询问,我们可以把三个区间分开处理再合并。直接维护复杂度过高,用 bitset 优化。由于这是个二进制序列,所以离散化的时候不能去重,否则答案就会偏大。

    直接操作容易 MLE,这里介绍一个小trick。我们可以把询问分批处理,这样就行了。

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <queue>
    #include <bitset>
    #include <cmath>
    
    using namespace std;
    typedef long long LL;
    typedef unsigned long long ULL;
    
    const int N = 1e5 + 5;
    const int F = 23333 + 5;
    int n, m, block, origin[N], appear[N];
    int cnt[N], ans[N], vis[25005];
    int l1[N], l2[N], l3[N];
    int r1[N], r2[N], r3[N];
    bitset < N > S[F];
    vector < int > disc;
    struct AskSet {
    	int l, r;
    	int id, p;
    } Q[N];
    
    int GetID(int x) {
    	return lower_bound(disc.begin(), disc.end(), x) - disc.begin() + 1;
    }
    
    bool SortWith(const AskSet& x, const AskSet& y) {
    	return (x.p < y.p) || (x.p == y.p && x.r < y.r);
    }
    
    void MakeCont(int pos, int flags, bitset < N >& bit) {
    	pos = origin[pos];
    	if (flags > 0) bit[pos + cnt[pos]] = 1;
    	else bit[pos + cnt[pos] - 1] = 0;
    	cnt[pos] += flags;
    }
    
    void Contribute(int fr, int ba) {
    	memset(cnt, 0, sizeof cnt);
    	memset(vis, 0, sizeof vis);
    	bitset < N > bit; bit.reset();
    	int l = 1, r = 0, subs = 0;
    	for (int i = fr; i <= ba; ++i) {
    		Q[++subs] = {l1[i], r1[i], i, appear[l1[i]]};
    		Q[++subs] = {l2[i], r2[i], i, appear[l2[i]]};
    		Q[++subs] = {l3[i], r3[i], i, appear[l3[i]]};
    		ans[i] += (r3[i] - l3[i]) + (r2[i] - l2[i]) + (r1[i] - l1[i]) + 3;
    	}
    	sort(Q + 1, Q + 1 + subs, SortWith);
    	for (int i = 1; i <= subs; ++i) {
    		while (r < Q[i].r) MakeCont(++r, 1, bit);
    		while (l > Q[i].l) MakeCont(--l, 1, bit);
    		while (r > Q[i].r) MakeCont(r--, -1, bit);
    		while (l < Q[i].l) MakeCont(l++, -1, bit);
    		if (!vis[Q[i].id - fr + 1]) {
    			vis[Q[i].id - fr + 1] = 1;
    			S[Q[i].id - fr + 1] = bit;
    		} else {
    			S[Q[i].id - fr + 1] &= bit;
    		}
    	}
    	for (int i = fr; i <= ba; ++i)
    		ans[i] -= S[i - fr + 1].count() * 3;
    }
    
    signed main() {
    	scanf("%d %d", &n, &m);
    	block = sqrt(n);
    	for (int i = 1; i <= n; ++i) {
    		scanf("%d", &origin[i]);
    		appear[i] = (i - 1) / block + 1;
    		disc.push_back(origin[i]);
    	}
    	sort(disc.begin(), disc.end());
    	for (int i = 1; i <= n; ++i)
    		origin[i] = GetID(origin[i]);
    	for (int i = 1; i <= m; ++i) {
    		scanf("%d %d", &l1[i], &r1[i]);
    		scanf("%d %d", &l2[i], &r2[i]);
    		scanf("%d %d", &l3[i], &r3[i]);
    	}
    	for (int i = 1; i <= m; i += 23333) Contribute(i, min(m, i + 23332));
    	for (int i = 1; i <= m; ++i) printf("%d
    ", ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    LeetCode "Median of Two Sorted Arrays"
    LeetCode "Distinct Subsequences"
    LeetCode "Permutation Sequence"

    LeetCode "Linked List Cycle II"
    LeetCode "Best Time to Buy and Sell Stock III"
    LeetCode "4Sum"
    LeetCode "3Sum closest"
    LeetCode "3Sum"
    LeetCode "Container With Most Water"
  • 原文地址:https://www.cnblogs.com/orchid-any/p/13800987.html
Copyright © 2011-2022 走看看