若 opt_i=1opti?=1,则接下来两个整数 p_i,x_ipi?,xi?,表示操作为在第 p_ipi? 个数后插入数 xx 。
若 opt_i=2opti?=2,则接下来一个整数 p_ipi?,表示操作为删除第 p_ipi? 个数。
若 opt_i=3opti?=3,则接下来两个整数 l_i,r_ili?,ri?,表示操作为翻转区间 [l_i,r_i][li?,ri?]。
若 opt_i=4opti?=4,则接下来两个整数 l_i,r_ili?,ri?,表示操作为查询区间 [l_i,r_i][li?,ri?] 的和。
强制在线规则:
令当前操作之前的最后一次 44 操作的答案为 lastanslastans(如果之前没有 44 操作,则 lastans=0lastans=0)。
则此次操作的 p_i,x_ipi?,xi? 或 l_i,r_ili?,ri? 均按位异或上 lastanslastans 即可得到真实的 p_i,x_ipi?,xi? 或 l_i,r_ili?,ri?。
输出格式
对于每个序号为 44 的查询操作,输出一行一个数表示区间的和。
输入输出样例
输入 #1复制
10 0 1 0 1 1 1 1 2 2 4 1 2 3 1 2 0 4 4 2 1 5 3 5 7 6 4 5 6 4 1 7 1 8 3 4 6 9 4 4 1
输出 #1复制
3 4 5 10
说明/提示
强制在线:以下针对 p_i,x_i,l_i,r_ipi?,xi?,li?,ri? 的限制均是按位异或 lastanslastans 后的限制。
对于 30\%30% 的数据,N\le 5000N≤5000。
对于另外 30\%30% 的数据,v_i=i-1vi?=i−1。
对于 100\%100% 的数据,1\le N\le 2\times 10^51≤N≤2×105,-10^6<x_i<10^6−106<xi?<106。
假设基于的历史版本的序列长度为 len\ge 1len≥1,有:
若 opt_i=1opti?=1,则 0\le p_i\le len0≤pi?≤len。
若 opt_i=2opti?=2,则 1\le p_i\le len1≤pi?≤len。
若 opt_i=3opti?=3,则 1\le l_i\le r_i\le len1≤li?≤ri?≤len。
若 opt_i=4opti?=4,则 1\le l_i\le r_i\le len1≤li?≤ri?≤len。
假设基于的历史版本的序列长度为 00,有:
opt_i=1opti?=1,p_i=0pi?=0。
果然期末考试前最好的解压方法就是码数据结构。。
感觉和主席树有异曲同工之妙(虽然我早就把主席树忘光了)
写的可持久化fhq treap
注意只用在split的时候新建,merge不需要再新建了
pushdown也要记得新建
注意long long
#include <bits/stdc++.h> using namespace std; inline long long read(){ long long f = 1, n = 0; char ch = getchar(); while(!isdigit(ch)){ if(ch == ‘-‘) f = -1; ch = getchar(); } while(isdigit(ch)){ n = (n << 1) + (n << 3) + (ch ^ 48); ch = getchar(); } return f * n; } template<typename T> inline void output(T x){ if(x < 0){ putchar(‘-‘); output(-x); } else{ if(x > 9) output(x / 10); putchar(x % 10 + 48); } } const int maxn = 200000 + 10; class Tree{ public: Tree(){ size = 0; sum = val = 0; ls = rs = 0; } Tree(int val): val(val){ ls = rs = 0; size = 1; sum = val; pri = rand(); tag = false; } int ls, rs, size, val, pri; long long sum; bool tag; }tree[maxn << 7]; int root[maxn], tcnt = 0; inline int newnode(int val){ tree[++tcnt] = Tree(val); return tcnt; } inline int copynode(int x){ tree[++tcnt] = tree[x]; return tcnt; } inline void pushup(int x){ tree[x].size = tree[tree[x].ls].size + tree[tree[x].rs].size + 1; tree[x].sum = tree[tree[x].ls].sum + tree[tree[x].rs].sum + tree[x].val; } inline void pushdown(int x){ if(tree[x].tag){ if(tree[x].ls) tree[x].ls = copynode(tree[x].ls); if(tree[x].rs) tree[x].rs = copynode(tree[x].rs); swap(tree[x].ls, tree[x].rs); tree[tree[x].ls].tag ^= 1; tree[tree[x].rs].tag ^= 1; tree[x].tag = false; } } void split(int x, int &a, int &b, int k){ if(!x){ a = b = 0; return; } pushdown(x); if(tree[tree[x].ls].size + 1 <= k){ a = copynode(x); split(tree[x].rs, tree[a].rs, b, k - tree[tree[x].ls].size - 1); pushup(a); } else{ b = copynode(x); split(tree[x].ls, a, tree[b].ls, k); pushup(b); } } void merge(int &x, int a, int b){ if(!a || !b){ x = a | b; return; } pushdown(a); pushdown(b); if(tree[a].pri < tree[b].pri){ x = a; merge(tree[x].rs, tree[a].rs, b); pushup(x); } else{ x = b; merge(tree[x].ls, a, tree[b].ls); pushup(x); } } int main(){ srand(19260817); int n = read(); root[0] = 0; int v, opt, a, b, c; long long p, x, l, r, lastans = 0; for(int i = 1; i <= n; i++){ v = read(); opt = read(); switch(opt){ case 1: p = read() ^ lastans; x = read() ^ lastans; split(root[v], a, b, p); merge(a, a, newnode(x)); merge(root[i], a, b); break; case 2: p = read() ^ lastans; split(root[v], a, b, p - 1); split(b, b, c, 1); merge(root[i], a, c); break; case 3: l = read() ^ lastans; r = read() ^ lastans; split(root[v], a, b, l - 1); split(b, b, c, r - l + 1); tree[b].tag = 1; merge(b, b, c); merge(root[i], a, b); break; case 4: l = read() ^ lastans; r = read() ^ lastans; split(root[v], a, b, l - 1); split(b, b, c, r - l + 1); output(lastans = tree[b].sum); putchar(‘\n‘); merge(b, b, c); merge(root[i], a, b); break; } } return 0; }
原文地址:https://www.cnblogs.com/ruoruoruo/p/12112811.html