[做题记录-数据结构] [Ynoi2014] 人人本着正义之名

吐了。

从早上开始写到下午四点一直不知道挂哪里了然后自暴自弃对别人题解改。

结果发现自己删点的时候情况漏了, 平移的时候漏了else, 然后变成别人的代码了

大概的想法是暴力维护极长的连续段, 然后左移右移都可以打标记实现, 具体来说就是先取出中间的, 然后讨论两边的是否受到影响而决定是否打标记。这个部分需要对于端点是0/1, 是否恰好存在某个端点细致讨论。

对于要删除的点, 要找到点以后使用一边的点进行覆盖, 注意由于端点的重复, 需要讨论当前的点是不是需要被删掉的点。

由于卡常数, 请手写内存池和(rand)函数。

#include <bits/stdc++.h>
#include <bits/extc++.h>

using namespace std;
using namespace __gnu_pbds;

class Input {
	#define MX 1000000
	private :
		char buf[MX], *p1 = buf, *p2 = buf;
		inline char gc() {
			if(p1 == p2) p2 = (p1 = buf) + fread(buf, 1, MX, stdin);
			return p1 == p2 ? EOF : *(p1 ++);
		}
	public :
		Input() {
			#ifdef Open_File
				freopen("a.in", "r", stdin);
				freopen("a.out", "w", stdout);
			#endif
		}
		template <typename T>
		inline Input& operator >>(T &x) {
			x = 0; int f = 1; char a = gc();
			for(; ! isdigit(a); a = gc()) if(a == '-') f = -1;
			for(; isdigit(a); a = gc()) 
				x = x * 10 + a - '0';
			x *= f;
			return *this;
		}
		inline Input& operator >>(char &ch) {
			while(1) {
				ch = gc();
				if(ch != '
' && ch != ' ') return *this;
			}
		}
		inline Input& operator >>(char *s) {
			int p = 0;
			while(1) {
				s[p] = gc();
				if(s[p] == '
' || s[p] == ' ' || s[p] == EOF) break;
				p ++; 
			}
			s[p] = '';
			return *this;
		}
	#undef MX
} Fin;

class Output {
	#define MX 1000000
	private :
		char ouf[MX], *p1 = ouf, *p2 = ouf;
		char Of[105], *o1 = Of, *o2 = Of;
		void flush() { fwrite(ouf, 1, p2 - p1, stdout); p2 = p1; }
		inline void pc(char ch) {
			* (p2 ++) = ch;
			if(p2 == p1 + MX) flush();
		}
	public :
		template <typename T> 
		inline Output& operator << (T n) {
			if(n < 0) pc('-'), n = -n;
			if(n == 0) pc('0');
			while(n) *(o1 ++) = (n % 10) ^ 48, n /= 10;
			while(o1 != o2) pc(* (--o1));
			return *this; 
		}
		inline Output & operator << (char ch) {
			pc(ch); return *this; 
		}
		inline Output & operator <<(const char *ch) {
			const char *p = ch;
			while( *p != '' ) pc(* p ++);
			return * this;
		}
		~Output() { flush(); } 
	#undef MX
} Fout;

#define cin Fin
#define cout Fout
#define endl '
'

using LL = long long;
using uint = unsigned int;

const int N = 3e6 + 10;
const int INF = 0x3f3f3f3f;

struct Node {
	int rnd;
	int col, sum, sz[2], l, r, dl, dr, minlen[2];
	Node *ls, *rs;
	Node() {}
	Node(int _rnd, int _col, int _l, int _r) {
		rnd = _rnd;
		col = _col;
		l = _l;
		r = _r;
		ls = rs = NULL;
		sum = 0;
		set();
	}
	void set() {
		sz[col] = 1; sz[! col] = 0;
		sum = col * (r - l + 1);
		dl = dr = 0;
		minlen[col] = r - l + 1; minlen[! col] = INF;
	}
	void modify(int tag_l, int tag_r) {
		dl += tag_l; dr += tag_r;
		minlen[0] -= tag_l + tag_r; minlen[1] += tag_l + tag_r;
		sum += (tag_l + tag_r) * sz[1];
		if(col == 1) this -> l -= tag_l, this -> r += tag_r;
		else this -> l += tag_r, this -> r -= tag_l;
	}
	void pushdown() {
		if(! dl && ! dr) return ;
		if(ls != NULL) ls -> modify(dl, dr);
		if(rs != NULL) rs -> modify(dl, dr);
		dl = dr = 0; return ;
	}
	void update() {
		set();
		if(ls != NULL) *this = *this + *(this -> ls);
		if(rs != NULL) *this = *this + *(this -> rs);
		return ;
	}
	inline Node operator +(const Node &t) const {
		Node res = * this;
		res.sum += t.sum;
		res.sz[0] += t.sz[0]; res.sz[1] += t.sz[1];
		res.minlen[0] = min(res.minlen[0], t.minlen[0]);
		res.minlen[1] = min(res.minlen[1], t.minlen[1]);
		return res;
	}
} ;

static const long long kMul = 0x9ddfea08eb382d69ULL;
long long Seed = 1145141919810;
inline long long fingerPrint(long long x) {
    return x *= kMul, x ^= x >> 47, x *= kMul, x ^= x >> 47, x *= kMul, x ^= x >> 47, x * kMul;
}
inline int frand(void) { return Seed += fingerPrint(Seed); }

const int PoolSz = 1e7;

Node pool[PoolSz]; 
int pooltop;

inline Node * newNode(int val, int l, int r) { return & (pool[pooltop ++] = Node(frand(), val, l, r)); }

class FhqTreap {
	private :
		Node *root;
		queue<Node *> EraseNode;
		// 找到要删除的点
		void FindEmpty(Node *x) {
			if(x == NULL) return ;
			if(x -> minlen[0] && x -> minlen[1]) return ;
			x -> pushdown();
			if(x -> l > x -> r) EraseNode.push(x);
			FindEmpty(x -> ls);
			FindEmpty(x -> rs);
		}
		// 删除需要删除的点
		void EraseEmpty() {
			while(EraseNode.size()) {
				Node *x = EraseNode.front(); EraseNode.pop();
				Node *nodeL = NULL, *treeM = NULL, *nodeR = NULL, *treeR = NULL;
				split_left(root, root, treeR, x -> l - 1);
				split_left(treeR, treeM, treeR, x -> l);
				split_right(root, root, nodeL, x -> l - 2);
				//assert(treeM -> sz[0] + treeM -> sz[1] == 1);
				if(x == treeM)
					nodeR = (x -> ls == NULL) ? x -> rs : x -> ls;
				else
					nodeR = treeM, nodeR -> ls = nodeR -> rs = NULL;
				/*
					treeM中存储了不合法的部分以及合法的部分, nodeR是要被左边覆盖掉的节点。
				*/
				if(nodeL != NULL && nodeR != NULL) nodeL -> r = nodeR -> r, nodeL -> set(), nodeR = NULL;
				root = merge(root, nodeL);
				root = merge(root, nodeR);
				root = merge(root, treeR);
			}
		}
		void split_left(Node *now, Node *&x, Node *&y, int k) {
			if(now == NULL) {
				x = y = NULL; return ;
			}
			now -> pushdown();
			if(now -> l <= k) 
				x = now, split_left(now -> rs, x -> rs, y, k);
			else
				y = now, split_left(now -> ls, x, y -> ls, k);
			now -> update();
		}
		void split_right(Node *now, Node *&x, Node *&y, int k) {
			if(now == NULL) {
				x = y = NULL; return ;
			}
			now -> pushdown();
			if(now -> r <= k) 
				x = now, split_right(now -> rs, x -> rs, y, k);
			else
				y = now, split_right(now -> ls, x, y -> ls, k);
			now -> update();
		}
		Node *merge(Node *x, Node *y) {
			if(x == NULL) return y;
			if(y == NULL) return x;
			x -> pushdown();
			y -> pushdown();
			if(x -> rnd < y -> rnd) {
				x -> rs = merge(x -> rs, y);
				x -> update(); return x;
			}
			else {
				y -> ls = merge(x, y -> ls);
				y -> update(); return y;
			}
		}
	public :
		FhqTreap() {
			root = NULL;
		}
		void Push(int l, int r, int val) {
			Node *p = newNode(val, l, r);
			root = merge(root, p);
		}
		void opt12(int l, int r, int val) {
			Node *nodeL = NULL, *p = NULL, *nodeR = NULL, *treeR = NULL;
			split_right(root, root, p, l - 1);
			split_left(p, p, treeR, r);
			split_left(p, nodeL, p, l - 1);
			split_right(p, p, nodeR, r);
			/*
          		p左右端点属于 [l, r]
        	   	nodeL左端点小于等于l - 1
           		nodeR右端点大于等于r + 1
        	   	右端点小于等于 l - 1在root
       		*/
			if(nodeL != NULL) {
				if(nodeL -> r > r) nodeR = newNode(nodeL -> col, r, nodeL -> r);
				nodeL -> r = l - 1;
				nodeL -> set();
			}
			else split_right(root, root, nodeL, l - 2);
			/*
				查看是否有区间跨越左端点, 没有的话就本身存在这样的区间, 从左边分一点
			*/
			if(nodeR != NULL)
				nodeR -> l = r + 1, nodeR -> set();
			else
				split_left(treeR, nodeR, treeR, r + 1);
			/*
				同理
			*/
			p = newNode(val, l, r);
			if(nodeL != NULL && p -> col == nodeL -> col) {
				p -> l = nodeL -> l; p -> set();
				nodeL = NULL;
			}
			if(nodeR != NULL && p -> col == nodeR -> col) {
				p -> r = nodeR -> r; p -> set();
				nodeR = NULL;
			}
			/*
				决定合并方向
			*/
			root = merge(root, nodeL);
			root = merge(root, p);
			root = merge(root, nodeR);
			root = merge(root, treeR);
		}
		// 颜色段左移
		void opt3(int l, int r) {
			r --;
			Node *treeM = NULL, *treeR = NULL, *node = NULL;
			split_right(root, root, treeM, l - 1);
			split_left(treeM, treeM, treeR, r);
			split_left(treeM, node, treeM, l);
			/*
				取出在[l + 1, r]的放入treeM, 特判左端点为l的区间
			*/
			if(node != NULL && node -> col == 1) root = merge(root, node); // 已经是1, 不影响
			else treeM = merge(node, treeM); //放入中间, 一起影响
			node = NULL;
			split_right(treeM, treeM, node, r - 1); // 查看右端点
			if(node != NULL && node -> col == 0) { 
				if(node -> r > r) 
					treeR = merge(node, treeR); // 没有影响
				else {
					treeM = merge(treeM, node); // 一起左移
					Node * nodeR = NULL;
					split_left(treeR, nodeR, treeR, r + 1);
					// 右端点是0, 所以加入一个扩展段
					treeM = merge(treeM, nodeR);
				}
			}
			else
				treeM = merge(treeM, node); // 是1直接扩展
			if(treeM != NULL) treeM -> modify(1, 0);
			root = merge(root, treeM);
			root = merge(root, treeR);
			FindEmpty(root); EraseEmpty();
		}
		void opt5(int l, int r) {
			r --;
			Node *treeM = NULL, *treeR = NULL, *node = NULL;
			split_right(root, root, treeM, l - 1);
			split_left(treeM, treeM, treeR, r);
			split_left(treeM, node, treeM, l);
			if(node != NULL && node -> col == 0) root = merge(root, node);
			else treeM = merge(node, treeM);
			node = NULL;
			split_right(treeM, treeM, node, r - 1);
			if(node != NULL && node -> col == 1) {
				if(node -> r > r) 
					treeR = merge(node, treeR);
				else {
					treeM = merge(treeM, node);
					Node * nodeR = NULL;
					split_left(treeR, nodeR, treeR, r + 1);
					treeM = merge(treeM, nodeR);
				}
			}
			else
				treeM = merge(treeM, node);
			if(treeM != NULL) treeM -> modify(0, -1);
			root = merge(root, treeM);
			root = merge(root, treeR);
			FindEmpty(root); EraseEmpty();
		}
		void opt4(int l, int r) {
			l ++;
			Node *treeM = NULL, *treeR = NULL, *node = NULL;
			split_right(root, root, treeM, l - 1);
			split_left(treeM, treeM, treeR, r);
			split_left(treeM, node, treeM, l);
			if(node != NULL && node -> col == 0) {
				if(node -> l < l) root = merge(root, node);
				else {
					treeM = merge(node, treeM);
					Node *nodeL = NULL;
					split_right(root, root, nodeL, l - 2);
					treeM = merge(nodeL, treeM);
				}
			}
			else treeM = merge(node, treeM);
			node = NULL;
			split_right(treeM, treeM, node, r - 1);
			if(node != NULL && node -> col == 1) treeR = merge(node, treeR);
			else treeM = merge(treeM, node);
			if(treeM != NULL) treeM -> modify(0, 1);
			root = merge(root, treeM);
			root = merge(root, treeR);
			FindEmpty(root); EraseEmpty();
		}
		void opt6(int l, int r) {
			l ++;
			Node *treeM = NULL, *treeR = NULL, *node = NULL;
			split_right(root, root, treeM, l - 1);
			split_left(treeM, treeM, treeR, r);
			split_left(treeM, node, treeM, l);
			if(node != NULL && node -> col == 1) {
				if(node -> l < l) root = merge(root, node);
				else {
					treeM = merge(node, treeM);
					Node *nodeL = NULL;
					split_right(root, root, nodeL, l - 2);
					treeM = merge(nodeL, treeM);
				}
			}
			else treeM = merge(node, treeM);
			node = NULL;
			split_right(treeM, treeM, node, r - 1);
			if(node != NULL && node -> col == 0) treeR = merge(node, treeR);
			else treeM = merge(treeM, node);
			if(treeM != NULL) treeM -> modify(-1, 0);
			root = merge(root, treeM);
			root = merge(root, treeR);
			FindEmpty(root); EraseEmpty();
		}
		int opt7(int l, int r) {
			Node *node = NULL, *p = NULL, *treeR = NULL;
			split_right(root, root, p, l - 1);
			split_left(p, p, treeR, r);
			int ans = 0;
			if(p != NULL) ans += p -> sum;
			split_left(p, node, p, l - 1);
			if(node != NULL) ans -= node -> col * (l - node -> l);
			p = merge(node, p);
			node = NULL;
			split_right(p, p, node, r);
			if(node != NULL) ans -= node -> col * (node -> r - r);
			p = merge(p, node);
			root = merge(root, p);
			root = merge(root, treeR);
			return ans;
		}
} ;

FhqTreap treap;

int n, m;

int a[N];

int main() {
	cin >> n >> m;
	for(int i = 1; i <= n; i ++) cin >> a[i];
	int lst = 1;
	for(int i = 2; i <= n; i ++)
		if(a[i] != a[i - 1]) treap.Push(lst, i - 1, a[i - 1]), lst = i;
	treap.Push(lst, n, a[n]);
	lst = 0;
	while(m --) {
		int opt, l, r;
		cin >> opt >> l >> r;
		l ^= lst; r ^= lst;
		if(opt == 1) treap.opt12(l, r, 0);
		if(opt == 2) treap.opt12(l, r, 1);
		if(opt == 3) treap.opt3(l, r);
		if(opt == 4) treap.opt4(l, r);
		if(opt == 5) treap.opt5(l, r);
		if(opt == 6) treap.opt6(l, r);
		if(opt == 7) {
			lst = treap.opt7(l, r);
			cout << lst << endl;
		}
	}
	return 0;
}
原文地址:https://www.cnblogs.com/clover4/p/15259207.html