1. 程式人生 > 其它 >P6136 【模板】普通平衡樹(資料加強版)

P6136 【模板】普通平衡樹(資料加強版)

【模板】普通平衡樹(資料加強版)

題目背景

本題是 P3369 資料加強版,**擴大資料範圍**並增加了**強制線上**。 **題目的輸入、輸出和原題略有不同**,但需要支援的操作相同。

題目描述

您需要寫一種資料結構(可參考題目標題),來維護一些整數,其中需要提供以下操作:
  1. 插入一個整數 \(x\)
  2. 刪除一個整數 \(x\)(若有多個相同的數,只刪除一個)。
  3. 查詢整數 \(x\) 的排名(排名定義為比當前數小的數的個數 \(+1\))。
  4. 查詢排名為 \(x\) 的數(如果不存在,則認為是排名小於 \(x\) 的最大數。保證 \(x\) 不會超過當前資料結構中數的總數)。
  5. \(x\) 的前驅(前驅定義為小於 \(x\),且最大的數)。
  6. \(x\) 的後繼(後繼定義為大於 \(x\),且最小的數)。

本題強制線上,保證所有操作合法(操作 \(2\) 保證存在至少一個 \(x\),操作 \(4,5,6\) 保證存在答案)。

輸入輸出格式

輸入格式


第一行兩個正整數 $n,m$,表示**初始數的個數**和操作的個數。

第二行 \(n\) 個整數 \(a_1,a_2,a_3,\ldots,a_n\),表示初始的數

接下來 \(m\) 行,每行有兩個整數 \(\text{opt}\)\(x'\)\(\text{opt}\)

表示操作的序號($ 1 \leq \text{opt} \leq 6 \(),\)x'$ 表示加密後的運算元。

我們記 \(\text{last}\) 表示上一次 \(3,4,5,6\) 操作的答案,則每次操作的 \(x'\) 都要異或\(\text{last}\) 才是真實的 \(x\)。初始 \(\text{last}\)\(0\)

輸出格式


輸出一行一個整數,表示所有 $3,4,5,6$ 操作的答案的**異或和**。

輸入輸出樣例

輸入樣例 #1

6 7
1 1 4 5 1 4
2 1
1 9
4 1
5 8
3 13
6 7
1 4

輸出樣例 #1

6

說明

### 樣例解釋

樣例加密前為:

6 7
1 1 4 5 1 4
2 1
1 9
4 1
5 9
3 8
6 1
1 0

限制與約定

對於 \(100\%\) 的資料,\(1\leq n\leq 10^5\)\(1\leq m\leq 10^6\)\(0\leq a_i,x\lt 2^{30}\)

本題輸入資料較大,請使用較快的讀入方式。

#include <bits/stdc++.h>

using namespace std;

#define getsize(x) (x ? x -> size : 0) 

#define ll long long

const int MAXN = 1e6 + 10;

#define USE_FREAD  // 使用 fread  讀入,去註釋符號
#define USE_FWRITE // 使用 fwrite 輸出,去註釋符號

#ifdef USE_FREAD
namespace iB
{
	char buf[1 << 21], *p1 = buf, *p2 = buf;
}
#define getchar() (iB::p1 == iB::p2 && (iB::p2 = (iB::p1 = iB::buf) + fread(iB::buf, 1, 1 << 21, stdin), iB::p1 == iB::p2) ? EOF : *iB::p1++)
#endif
#ifdef USE_FWRITE
namespace oB
{
	char buf[1 << 21], *p1 = buf, *p2 = buf + (1 << 21);
}
#define putchar(ch) ((oB::p1 == oB::p2 && fwrite(oB::p1 = oB::buf, 1, 1 << 21, stdout)), *oB::p1++ = ch)
#endif
namespace Fastio
{
	struct Reader
	{
		char endch;
		Reader()
		{
			endch = '\0';
		}
		Reader& operator >> (char &ch)   // ignore character ' ', '\r', '\n', '\t'
		{
			ch = getchar();
			while (ch == ' ' || ch == '\r' || ch == '\n' || ch == '\t') ch = getchar();
			return *this;
		}
		Reader& operator >> (char *str)
		{
			while (((*str = getchar()) == ' ' || *str == '\n' || *str == '\r' || *str == '\t') && *str != EOF);
			while ((*++str = getchar()) != ' ' && *str != '\n' && *str != '\r' && *str != '\t' && *str != EOF);
			*str = '\0';
			return *this;
		}
		template <typename Int>
		Reader& operator >> (Int &d)
		{
			bool flag = 0;
			endch = getchar();
			while ((!isdigit(endch)) && endch != '-' && endch != EOF) endch = getchar();
			if (endch == '-') flag = 1, endch = getchar();
			d = endch & 15;
			while (isdigit(endch = getchar())) d = (d << 3) + (d << 1) + (endch & 15);
			if (flag) d = -d;
			return *this;
		}
		template <typename T>
		inline T get()
		{
			T Val;
			(*this) >> Val;
			return Val;
		}
	};

	struct Writer
	{
		~Writer()
		{
#ifdef USE_FWRITE
			fwrite(oB::buf, 1, oB::p1 - oB::buf, stdout);
#endif
		}
		Writer& operator << (const char ch)
		{
			putchar(ch);
			return *this;
		}
		Writer& operator << (const char *ch)
		{
			while (*ch) putchar(*(ch++));
			return *this;
		}
		Writer& operator << (char* ss)
		{
			return *this << (const char *)ss;
		}
		template <typename Int>
		Writer& operator << (Int x)
		{
			static char buffer[33];
			static int top = 0;
			if (!x)
			{
				putchar('0');
				return *this;
			}
			if (x < 0) putchar('-'), x = -x;
			while (x)
			{
				buffer[++top] = '0' | (x % 10);
				x /= 10;
			}
			while (top) putchar(buffer[top--]);
			return *this;
		}
	};
	void flush_output()
	{
#ifdef USE_FWRITE
		fwrite(oB::buf, 1, oB::p1 - oB::buf, stdout);
		oB::p1 = oB::buf;
#else
		fflush(stdout);
#endif
	}
}
Fastio::Reader kin;
Fastio::Writer kout;

class FHQ
{
    public :
        class Node
        {
            public :
                ll key, rank;
                int size;
                Node *ls, *rs;
                void push_up()
                {
                    size = getsize(ls) + getsize(rs) + 1;
                }
        }pool[2 * MAXN], *rt;

        int top;
        //分裂 p 返回 p 的左子p_l, 右子p_r
        void split(Node *p , Node *&p_l, Node *&p_r, int x)//分裂當前子樹
        {
            if(!p)//p 為空,無需分離
            {
                p_l = p_r = NULL;
                return ;
            }

            if(p -> key <= x)//如果 p 的值比 x 小,就把 p 接到左子上,繼續分裂 p 的右子
            {
                p_l = p;
                split(p -> rs, p_l -> rs, p_r, x);
                p_l -> push_up();
            }

            else//否則分 p 的左子
            {
                p_r = p;
                split(p -> ls, p_l ,p_r -> ls, x);
                p_r -> push_up();
            }

        }

        void merge(Node *&p, Node *p_l, Node *p_r)
        {
            if(!p_l || !p_r)
            {
                p = p_l ? p_l : p_r;
                return ;
            }

            if(p_l -> rank < p_r -> rank)
            {
                p = p_l;
                merge(p -> rs, p_l -> rs, p_r);
            }

            else
            {
                p = p_r;
                merge(p -> ls, p_l, p_r -> ls);
            }
            p -> push_up();
        }

        Node *newNode(int x)
        {
            Node *p = pool + (++top);
            p -> key = x;
            p -> rank = rand();
            p -> size = 1;
            return p;
        }

        void insert(Node *&rt, int x)
        {
            Node *p1, *p2;
            split(rt, p1, p2 ,x - 1);
            merge(rt, p1 ,newNode(x));
            merge(rt, rt, p2);
        }

        void remove(Node *&rt, int x)
        {
            Node *p1, *p2, *p3 , *p4;
            split(rt, p1 ,p2 ,x - 1);
            split(p2, p3 ,p4, x);
            merge(p3, p3 -> ls, p3 -> rs);
            merge(p3, p3, p4);
            merge(rt, p1, p3);
        }

        ll getRank(Node *&rt, int x)
        {
            Node *p1 ,*p2;
            split(rt, p1 ,p2, x - 1);

            ll ans = getsize(p1);
            merge(rt, p1 ,p2);
            return ans;
        }

        ll getKey(Node *p, ll rank)
        {
            while(p)
            {
                if(rank <= getsize(p -> ls))
                    p = p -> ls;
                else if(rank > getsize(p -> ls) + 1)
                {
                    rank -= getsize(p -> ls) + 1;
                    p = p -> rs;
                }
                else return p -> key;
            }
            return 0;
        }

        ll lower(Node *p, ll x)
        {
            ll ans = INT_MIN;
            while(p)
            {
                if(x > p -> key)
                {
                    ans = max(ans, p -> key);
                    p = p -> rs;
                }
                else p = p -> ls;
            }
            return ans;
        }

        ll upper(Node *p, int x)
        {
            ll ans = INT_MAX;
            while(p)
            {
                if(x < p -> key)
                {
                    ans = min(ans, p -> key);
                    p = p -> ls;
                }
                else p = p -> rs;
            }
            return ans;
        }

}FHQ;

int t;

int op;

ll x;

long long ans;

int n;

ll last;

int main()
{
   // scanf("%d %d", &n,&t);

    kin >> n >> t;

    for(int i = 1; i <= n; i++)
    {
        //scanf("%lld", &x);
        kin >> x;
        FHQ.insert(FHQ.rt, x);
    }

    while(t--)
    {
        //scanf("%d %lld", &op, &x);
        kin >> op >> x;
        x ^= last;
        if(op == 1)
        {
            FHQ.insert(FHQ.rt, x);
        }

        if(op == 2)
        {
            FHQ.remove(FHQ.rt, x);
        }
        if(op == 3)
        {
            last = FHQ.getRank(FHQ.rt, x) + 1;
            ans ^= last;
        }

        if(op == 4)
        {
            last = FHQ.getKey(FHQ.rt, x);
            ans ^= last;
        }

        if(op == 5)
        {
            last = FHQ.lower(FHQ.rt, x);
            ans ^= last;
        }
        if(op == 6)
        {
            last = FHQ.upper(FHQ.rt, x);
            ans ^= last;
        }

       // printf("%lld\n", last);

    }

    kout << ans;

    //printf("%lld", ans);

    return 0;
}