题目都是图片,就不给了,就给链接好了
由于bzoj比较慢,就先给[vjudge传送门]
有兴趣的可以去逛bzoj[bzoj传送门]
题目大意
有n个数a[1],a[2],...,a[n],它们开始都是0,现在有两种操作
1)C l r k,给a[k]赋值为(a[l], a[r])
2)Q l r,找到a[l], a[l + 1], ..., a[r]中的最大值,并输出它的下标,如果有多个最大值,则输出最小的那一个。
对于数对的比较,在题目中是这么定义的
对于任意x, y,若x = 0, y ≠ 0,则有x < y,例如,0 < (0, 0), 0 < (0, (0, 0))
对于任意数对x, y,若x ≠ 0, y ≠ 0,则先比较第一关键字,再比较第二关键字,因为题目中的数对是递归定义的,所以比较起来可能有点麻烦,例如(0, 0) < (0, (0, (0, 0))), (((0, (0, 0)), (0, 0)), 0) > ((0, 0), (0, 0)), 0)
解题思路
先想一下暴力吧,暴力想不出来想正解可能有点困难。暴力思路很简单,线段树维护区间最大值,递归比较,虽然会T掉,但是方法可以优化。
我可以考虑将这些数映射到一个实数区间$[0, 1]$上,让平衡树的每一个节点代表一个实数区间(想想为什么,不然再插一个节点到它下面,这个实数值怎么算?)。进行比较当在生成一个数的时候,我把它插进平衡树里,返回一个它的实数值。这样就可以实现$O(1)$比较。
至于用哪种平衡树呢,有待思考。我们知道很多平衡树在维护自己的平衡时通常会变得乱糟糟的,因此这个实数区间如果按照原来的实数区间继续做的话会出问题,比如旋转,左端点更小的旋转上来了,这个怎么玩。。一看就会出问题。。所以必须重新计算实数区间。现在作这样规定,若父节点的实数区间为$[vl, vr]$,则它的左子树的实数区间为$[vl, \frac{vl + vr}{2}]$,右子树的实数区间为$[\frac{vl + vr}{2}]$,如果你高兴,可以把$2$改成$3$。
假设我们用Splay来维护这个映射,当我们插入一个节点或者查询一次岂不是就要重新计算整个树的实数区间吗?也就是说还不如上面的暴力。所以需要重量平衡树,比如替罪羊树。替罪羊树在重构的时候可以顺便把实数区间处理出来。由于重构后对应数对的实数值(就去这个区间的mid吧)也会改变,所以之前的返回实数不可行,只能返回对应的节点,大不了比较的时候多写几行代码。因为替罪羊树深度有保证,所以精度不会炸。
接着再按返回回来的节点代表的实数值作比较,用线段树维护区间最大值,最大值的下标。再开一个数组记录一下对应位上当前映射到的节点上,这样对于修改操作不会那么麻烦。
另外,平衡因子取0.75左右比较快。
(其实这个东西是超现实数,可以建立和实数的一一映射)
Code
/**
* bzoj
* Problem#3600
* Accepted
* Time:8420ms
* Memory:18584k
*/
#include<iostream>
#include<fstream>
#include<cstdio>
#include<ctime>
#include<cctype>
#include<cstring>
#include<cstdlib>
#include<fstream>
#include<sstream>
#include<algorithm>
#include<map>
#include<set>
#include<queue>
#include<vector>
#include<stack>
using namespace std;
typedef bool boolean;
#define inf 0xfffffff
#define smin(a, b) a = min(a, b)
#define smax(a, b) a = max(a, b)
template<typename T>
inline void readInteger(T& u){
char x;
int aFlag = ;
while(!isdigit((x = getchar())) && x != '-');
if(x == '-'){
x = getchar();
aFlag = -;
}
for(u = x - ''; isdigit((x = getchar())); u = (u << ) + (u << ) + x - '');
ungetc(x, stdin);
u *= aFlag;
} template<typename T>
class Pair {
public:
T l, r;
Pair(T l = NULL, const T r = NULL):l(l), r(r) { } boolean operator < (Pair b) {
if(l->val != b.l->val) return l->val < b.l->val;
return r->val < b.r->val;
}
}; #define Node ScapegoatTreeNode*
typedef class ScapegoatTreeNode {
private:
const static double factor = 0.73;
public:
double l, r;
double val;
ScapegoatTreeNode* next[];
Pair<Node> p;
int s; ScapegoatTreeNode():l(), r(), val(), s() {
next[] = next[] = NULL;
}
ScapegoatTreeNode(double l, double r, Pair<Node> p):l(l), r(r), val((l + r) / ), s(), p(p) {
next[] = next[] = NULL;
} void maintain() {
s = ;
for(int i = ; i < ; i++)
if(next[i])
s += next[i]->s;
} boolean bad() {
for(int i = ; i < ; i++)
if(next[i] && next[i]->s > (s + ) * factor)
return true;
return false;
}
}ScapegoatTreeNode; typedef class ScapegoatTree {
public:
ScapegoatTreeNode* root;
vector<ScapegoatTreeNode*> lis; ScapegoatTree():root(NULL) { } void travel(ScapegoatTreeNode*& node) {
if(node->next[] != NULL) travel(node->next[]);
lis.push_back(node);
if(node->next[] != NULL) travel(node->next[]);
node->next[] = node->next[] = NULL;
node->s = ;
} ScapegoatTreeNode* rebuild(int l, int r, double vl, double vr) {
if(l > r) return NULL;
int mid = (l + r) >> ;
ScapegoatTreeNode*& node = lis[mid];
double vmid = (vl + vr) / ;
node->l = vl, node->r = vr, node->val = vmid;
node->next[] = rebuild(l, mid - , vl, vmid);
node->next[] = rebuild(mid + , r, vmid, vr);
node->maintain();
return node;
} void remake(ScapegoatTreeNode*& node, ScapegoatTreeNode*& father) {
lis.clear();
travel(node);
int l = , r = lis.size() - ;
ScapegoatTreeNode*& newroot = lis[(l + r) >> ];
rebuild(l, r, node->l, node->r);
if(father != NULL) father->next[(father->next[] == node) ? () : ()] = newroot;
else this->root = newroot;
} ScapegoatTreeNode* insert(ScapegoatTreeNode*& node, double vl, double vr, Pair<Node> p, ScapegoatTreeNode*& bad, ScapegoatTreeNode*& bf) {
double vmid = (vl + vr) / ;
if(node == NULL) {
node = new ScapegoatTreeNode(vl, vr, p);
return node;
}
if(node->p.l->val == p.l->val && node->p.r == p.r) return node;
ScapegoatTreeNode* ret;
if(p < node->p) ret = insert(node->next[], vl, vmid, p, bad, bf);
else ret = insert(node->next[], vmid, vr, p, bad, bf);
if(bad != NULL && bf == NULL) bf = node;
if(node->bad()) bad = node, bf = NULL;
node->maintain();
return ret;
} ScapegoatTreeNode* insert(Pair<Node> p) {
ScapegoatTreeNode* bad = NULL, *fa = NULL, *ret;
ret = insert(root, 0.0, 1.0, p, bad, fa);
if(bad != NULL) remake(bad, fa);
return ret;
}
}ScapegoatTree; ScapegoatTreeNode zero(, , Pair<Node>());
Pair<Node> pzero(&zero, &zero); typedef class SegTreeNode {
public:
Node val;
int maxid;
SegTreeNode* l, *r;
SegTreeNode(Node val = NULL, SegTreeNode* l = NULL, SegTreeNode* r = NULL):val(val), l(l) ,r(r) { } inline void pushUp() {
if(r->val->val < l->val->val)
val = l->val, maxid = l->maxid;
else if(l->val->val < r->val->val) val = r->val, maxid = r->maxid;
else val = l->val, maxid = l->maxid;
}
}SegTreeNode; typedef class SegTree {
public:
SegTreeNode* root; SegTree():root(NULL) { }
SegTree(int size){
build(root, , size);
} void build(SegTreeNode*& node, int l, int r) {
node = new SegTreeNode();
if(l == r) {
node->val = &zero;
node->maxid = l;
return;
}
int mid = (l + r) >> ;
build(node->l, l, mid);
build(node->r, mid + , r);
node->pushUp();
} void update(SegTreeNode*& node, int l, int r, Node val, int index) {
if(l == index && r == index) {
node->val = val;
return;
}
int mid = (l + r) >> ;
if(index <= mid)
update(node->l, l, mid, val, index);
else update(node->r, mid + , r, val, index);
node->pushUp();
} void query(SegTreeNode*& node, int l, int r, int ql, int qr, Node& maxv, int& index) {
if(l == ql && r == qr) {
if(maxv->val < node->val->val) {
maxv = node->val;
index = node->maxid;
} else if(maxv->val == node->val->val)
smin(index, node->maxid);
return;
}
int mid = (l + r) >> ;
if(qr <= mid) query(node->l, l, mid, ql, qr, maxv, index);
else if(ql > mid) query(node->r, mid + , r, ql, qr, maxv, index);
else {
query(node->l, l, mid, ql, mid, maxv, index);
query(node->r, mid + , r, mid + , qr, maxv, index);
}
} int query(int l, int r, int n) {
Node maxv = &zero;
int index = inf;
query(root, , n, l, r, maxv, index);
return index;
}
}SegTree; int n, m;
ScapegoatTree vm;
SegTree st;
Node* lis;
char buf[]; inline void init() {
readInteger(n);
readInteger(m);
st = SegTree(n);
lis = new Node[(const int)(n + )];
for(int i = ; i <= n; i++)
lis[i] = &zero;
} inline void solve() {
for(int i = , a, b, c; i <= m; i++) {
scanf("%s%d%d", buf, &a, &b);
if(buf[] == 'C') {
readInteger(c);
lis[c] = vm.insert(Pair<Node>(lis[a], lis[b]));
st.update(st.root, , n, lis[c], c);
} else {
printf("%d\n", st.query(a, b, n));
}
}
} int main() {
init();
solve();
return ;
}