BZOJ 1180: [CROATIAN2009]OTOCI

时间:2023-03-08 18:49:05
BZOJ 1180: [CROATIAN2009]OTOCI

1180: [CROATIAN2009]OTOCI

Time Limit: 50 Sec  Memory Limit: 162 MB
Submit: 989  Solved: 611
[Submit][Status][Discuss]

Description

给出n个结点以及每个点初始时对应的权值wi。起始时点与点之间没有连边。有3类操作:

1、bridge A B:询问结点A与结点B是否连通。如果是则输出“no”。否则输出“yes”,并且在结点A和结点B之间连一条无向边。

2、penguins A X:将结点A对应的权值wA修改为X。

3、excursion A B:如果结点A和结点B不连通,则输出“impossible”。否则输出结点A到结点B的路径上的点对应的权值的和。

给出q个操作,要求在线处理所有操作。数据范围:1<=n<=30000, 1<=q<=300000, 0<=wi<=1000。

Input

第一行包含一个整数n(1<=n<=30000),表示节点的数目。

第二行包含n个整数,第i个整数表示第i个节点初始时对应的权值。

第三行包含一个整数q(1<=n<=300000),表示操作的数目。

以下q行,每行包含一个操作,操作的类别见题目描述。

Output

输出所有bridge操作和excursion操作对应的输出,每个一行。

Sample Input

5
4 2 4 5 6
10
excursion 1 1
excursion 1 2
bridge 1 2
excursion 1 2
bridge 3 4
bridge 3 5
excursion 4 5
bridge 1 3
excursion 2 4
excursion 2 5

Sample Output

4
impossible
yes
6
yes
yes
15
yes
15
16

HINT

任意时刻每个节点对应的权值都是1到1000的整数。

Source

[Submit][Status][Discuss]

又是一道LCT模板题,Splay上维护子树权值和,就相当于维护了路径权值和。

 #include <cstdio>

 template <class T>
inline void swap(T &a, T &b)
{
T c; c = a;
a = b;
b = c;
} const int mxn = ; int n, m; struct node
{
int val;
int sum;
node *son[];
node *father;
bool reverse; inline node(int v = )
{
val = v;
sum = v;
son[] = NULL;
son[] = NULL;
father = NULL;
reverse = false;
} inline void update(void)
{
sum = val; if (son[])sum += son[]->sum;
if (son[])sum += son[]->sum;
} inline bool isRoot(void)
{
if (father == NULL)
return true; if (father->son[] == this)
return false;
if (father->son[] == this)
return false; return true;
} inline void pushDown(void)
{
if (reverse)
{
reverse = false; swap(son[], son[]); if (son[])son[]->reverse ^= true;
if (son[])son[]->reverse ^= true;
}
}
}tree[mxn]; inline void connect(node *f, node *t, bool k)
{
if (t != NULL)t->father = f;
if (f != NULL)f->son[k] = t;
} inline void rotate(node *t)
{
node *f = t->father;
node *g = f->father; bool s = f->son[] == t; connect(f, t->son[!s], s);
connect(t, f, !s); t->father = g;
if (g && g->son[] == f)g->son[] = t;
if (g && g->son[] == f)g->son[] = t; f->update();
t->update();
} inline void push(node *t)
{
static node *stk[mxn]; int top = ; stk[top++] = t; while (!t->isRoot())
stk[top++] = t = t->father; while (top)stk[--top]->pushDown();
} inline void splay(node *t)
{
push(t); while (!t->isRoot())
{
node *f = t->father;
node *g = f->father; if (f->isRoot())
rotate(t);
else
{
bool a = f && f->son[] == t;
bool b = g && g->son[] == f; if (a == b)
rotate(f), rotate(t);
else
rotate(t), rotate(t);
}
}
} inline void access(node *t)
{
node *p = NULL; while (t != NULL)
{
splay(t);
t->son[] = p, t->update();
p = t, t = t->father;
}
} inline void makeRoot(node *t)
{
access(t), splay(t), t->reverse ^= true;
} inline void link(node *t, node *f)
{
makeRoot(t), t->father = f;
} inline void cut(node *t)
{
splay(t); if (t->son[])t->son[]->father = NULL;
if (t->son[])t->son[]->father = NULL; t->son[] = t->son[] = NULL, t->update();
} inline node *find(node *t)
{
access(t), splay(t); node *r = t; while (r->son[])
r = r->son[]; return r;
} signed main(void)
{
scanf("%d", &n); for (int i = , v; i <= n; ++i)
scanf("%d", &v), tree[i] = node(v); scanf("%d", &m); while (m--)
{
static int x, y;
static char s[]; scanf("%s%d%d", s, &x, &y); if (s[] == 'b')
{
if (find(tree + x) == find(tree + y))
puts("no");
else
puts("yes"), link(tree + x, tree + y);
}
else if (s[] == 'p')
{
access(tree + x), splay(tree + x);
tree[x].val = y, tree[x].update();
}
else
{
if (find(tree + x) != find(tree + y))
puts("impossible");
else
{
makeRoot(tree + x), access(tree + y), splay(tree + y);
printf("%d\n", tree[y].sum);
}
}
}
}

@Author: YouSiki