1 条题解

  • 0
    @ 2025-8-24 22:53:45

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar JiaY19
    会走到属于我的完美时间线吗

    搬运于2025-08-24 22:53:45,当前版本为作者最后更新于2023-12-26 14:40:57,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    思路

    比较典的 ODT 题目。

    发现排序是一个非常有性质的操作。

    它对区间的更改与颜色段均摊差不多。

    那么我们可以想到用 ODT 来维护这一整个序列。

    具体的,区间排序操作可以用 ODT 维护每次排序产生的段,每段用线段树维护排序后的结果。

    每次修改就可以进行线段树的分裂与合并。

    如何查询。

    可以发现,我们所查询的是一段前缀的颜色数量。

    那么只需维护每种颜色的最左出现位置。

    可以在线段树上维护每个权值的出现次数和是否是最左出现。

    另外再使用一个树状树组进行辅助修改,维护段的前缀答案。

    查询时需要查完整的段上最左出现的值个数的前缀和,以及在查询切开的段的线段树上查前缀即可。

    时间复杂度是一个常数巨大的单 log\log

    空间复杂度相同。

    Code

    这份没有卡常的代码只能勉强跑过,最慢点要 7.9s7.9s

    #include <bits/stdc++.h>
    using namespace std;
    
    #define x first
    #define y second
    #define fro(i, x, y) for (int i = (x); i <= (y);i++)
    #define pre(i, x, y) for (int i = (x); i >= (y);i--)
    
    typedef pair<int, int> PII;
    
    const int N = 1000010;
    const int M = N * 32;
    
    int n, m, a[N], t[N], rt[N], stk[N], ton[N], del[M];
    int cnt, top, tot, lol, vis[N], siz[M], val[M], s[M][2];
    
    struct Node
    {
    	int l;
    	mutable int r, id;
    	inline bool operator<(const Node& other) const
    		{ return l < other.l; }
    };
    
    set<Node> q;
    
    inline int lowbit(int x) { return x & (-x); }
    inline void delet(int x) { del[++cnt] = x; }
    inline int node()
    {
    	int x = (cnt ? del[cnt--] : ++tot);
    	val[x] = siz[x] = s[x][0] = s[x][1] = 0;
    	return x;
    }
    inline int pode()
    {
    	int x = (top ? stk[top--] : ++lol);
    	rt[x] = vis[x] = 0;
    	return x;
    }
    inline void add(int x, int k)
    	{ while (x <= n) t[x] += k, x += lowbit(x); }
    inline int ask(int x)
    	{ int res = 0; while(x) res += t[x], x -= lowbit(x); return res; }
    inline void push_up(int p)
    {
    	siz[p] = siz[s[p][0]] + siz[s[p][1]];
    	val[p] = val[s[p][0]] + val[s[p][1]];
    }
    inline void update(int &p, int k, int l = 1, int r = n)
    {
    	if(!p) p = node();
    	if (l == r)
    	{
    		siz[p]++, val[p] |= (ton[l] ^ 1), ton[l] |= 1;
    		return;
    	}
    	int mid = (l + r) / 2;
    	if(k <= mid)
    		update(s[p][0], k, l, mid);
    	else
    		update(s[p][1], k, mid + 1, r);
    	push_up(p);
    }
    inline int merge(int p1, int p2, int l = 1, int r = n)
    {
    	if(!p1 || !p2) return p1 + p2;
    	if(l == r)
    		return siz[p1] += siz[p2], val[p1] |= val[p2], delet(p2), p1;
    	int mid = (l + r) / 2;
    	s[p1][0] = merge(s[p1][0], s[p2][0], l, mid);
    	s[p1][1] = merge(s[p1][1], s[p2][1], mid + 1, r);
    	return delet(p2), push_up(p1), p1;
    }
    inline void split(int &p1, int &p2, int op, int k, int l = 1, int r = n)
    {
    	if(!p1) p1 = node();
    	if(l == r)
    	{
    		siz[p1] = k, siz[p2] -= k;
    		val[p1] = val[p2], val[p2] = 0;
    		if(siz[p2] == 0) delet(p2), p2 = 0;
    		return;
    	}
    	int mid = (l + r) / 2;
    	if(siz[s[p2][op]] <= k)
    	{
    		s[p1][op] = s[p2][op], k -= siz[s[p2][op]], s[p2][op] = 0;
    		if(k != 0)
    		{
    			if(op == 0) split(s[p1][!op], s[p2][!op], op, k, mid + 1, r);
    			else split(s[p1][!op], s[p2][!op], op, k, l, mid);
    		}
    	}
    	else
    	{
    		if(op == 0)
    			split(s[p1][op], s[p2][op], op, k, l, mid);
    		else
    			split(s[p1][op], s[p2][op], op, k, mid + 1, r);
    	}
    	push_up(p1), push_up(p2);
    	if (siz[p2] == 0)
    		delet(p2), p2 = 0;
    }
    inline auto split(int x)
    {
    	if(x > n) return q.end();
    	auto it = --q.upper_bound({x, 0, 0});
    	if ((*it).l == x) return it;
    	int nw = pode(); add((*it).r, -val[rt[(*it).id]]);
    	swap(nw, (*it).id), q.insert({x, (*it).r, nw}), (*it).r = x - 1;
    	split(rt[(*it).id], rt[nw], vis[nw], (*it).r - (*it).l + 1);
    	vis[(*it).id] = vis[nw];
    	add((*it).r, val[rt[(*it).id]]), it++;
    	add((*it).r, val[rt[(*it).id]]);
    	return it;
    }
    inline void change(int l, int r, int op)
    {
    	auto it1 = split(l);
    	auto it2 = split(r + 1);
    	int id = (*it1).id;
    	for (auto i = it1; i != it2; i++)
    	{
    		add((*i).r, -val[rt[(*i).id]]);
    		if (i != it1)
    			rt[id] = merge(rt[id], rt[(*i).id]), stk[++top] = (*i).id;
    	}
    	q.erase(it1, it2);
    	auto it = q.insert({l, r, id}).x;
    	add(r, val[rt[id]]), vis[id] = op;
    }
    inline int ask(int p, int k, int op, int l = 1, int r = n)
    {
    	if (!p || !k) return 0;
    	if(l == r) return val[p];
    	int mid = (l + r) / 2, sum = 0;
    	if (k >= siz[s[p][op]])
    	{
    		k -= siz[s[p][op]];
    		if(op == 0)
    			return val[s[p][op]] + ask(s[p][!op], k, op, mid + 1, r);
    		return val[s[p][op]] + ask(s[p][!op], k, op, l, mid);
    	}
    	if(op == 0)
    		return ask(s[p][op], k, op, l, mid);
    	return ask(s[p][op], k, op, mid + 1, r);
    }
    
    signed main()
    {
    	ios::sync_with_stdio(false), cin.tie(0);
    	cin >> n >> m;
    	fro(i, 1, n) cin >> a[i];
    	fro(i, 1, n)
    	{
    		++lol;
    		update(rt[lol], a[i]);
    		q.insert({i, i, lol});
    		add(i, val[rt[lol]]);
    	}
    	int lastans = 0;
    	fro(i, 1, m)
    	{
    		int l, r, c;
    		cin >> l >> r >> c;
    		l ^= lastans, r ^= lastans, c ^= lastans;
    		change(min(l, r), max(l, r), l >= r);
    		int s = (*(--q.upper_bound({c, 0, 0}))).l;
    		int x = (*(--q.upper_bound({c, 0, 0}))).id;
    		cout << (lastans = ask(rt[x], c - s + 1, vis[x]) + ask(c - 1)) << "\n";
    	}
    	return 0;
    }
    
    • 1

    信息

    ID
    9538
    时间
    8000ms
    内存
    512MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者