HDU-5967 小R与手机(LCT)

来源:互联网 发布:短域名生成算法 编辑:程序博客网 时间:2024/04/30 07:34

小R与手机

Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 456    Accepted Submission(s): 108


Problem Description
小R有n部手机,为了便于管理,他对一些手机设置了“呼叫转移”的功能。
具体来说,第i ( 1 <= i <= n )部手机有个参数 ai(0<=ai<=n,ai i )。若 ai  0 则表示第i部手机接到电话时会将电话无条件转移给第 ai部手机(此时如果 aai0, 会继续进行呼叫转移)。
如果一部手机接到电话会导致至少 109次呼叫转移,则这次电话无法接通。
现在有m个事件依次发生,具体如下:
1 x y表示将第x部手机的参数设置为y,即将 ax设置为y ;
2 x表示询问给第x部手机打电话,最终接到电话的手机编号(如果无法接通, 则编号为-1 )。
小R当然知道怎么做啦!但是他想考考你。
 

Input
只包含一组测试数据。
输入的第一行有两个整数n, m。保证1 <= n, m <= 2 * 105
接下来一行,包含n个整数,第i个整数为 ai
接下来m行,每一行为一个事件,具体格式见问题描述。
对于事件1,保证1 <= x <= n, 0 <= y <= n, x  y ;对于事件2,保证1 <= x <= n
 

Output
对每个询问事件输出一行一个整数,表示最终接到电话的手机编号,如果无法接 通,输出-1。
 

Sample Input
5 62 3 4 5 02 22 51 4 32 11 4 02 1
 

Sample Output
55-14

LCT,如果某次加边时会构成环,那么这条边的两端一定是根节点和其子树节点,每次加边的时候判断一下是否会构成环,会的话就保存好那条边,还要判断本来是否有环,有环的话要把环拆开并把保存好的边加入Splay-tree中

#include<bits/stdc++.h>#define rson m+1,r,rt<<1|1#define lson l,m,rt<<1#define FIN freopen("input.txt","r",stdin);using namespace std;typedef unsigned long long ULL;typedef long long LL;const int  MX = 2e5 + 5;typedef pair<int, int> PII;int n, m, a[MX];int ch[MX][2], pre[MX], clr[MX];bool root[MX];void init() {    for (int i = 0; i <= n; i++) {        ch[i][0] = ch[i][1] = clr[i] = 0;        pre[i] = 0;        root[i] = 1;    }}void Rotate(int x) {    int y = pre[x], kind = ch[y][1] == x;    ch[y][kind] = ch[x][!kind];    pre[ch[y][kind]] = y;    pre[x] = pre[y];    pre[y] = x;    ch[x][!kind] = y;    if (root[y]) root[y] = 0, root[x] = 1;    else ch[pre[x]][ch[pre[x]][1] == y] = x;}int t;void Splay(int x) {    while (!root[x]) {        int f = pre[x], ff = pre[f];        if (!root[f]) {            if ((ch[ff][1] == f) == (ch[f][1] == x)) Rotate(f);            else Rotate(x);        }        Rotate(x);    }}int Access(int x) {    int y = 0;    t = x;    while (x) {        Splay(x);        root[ch[x][1]] = 1;     //在辅助树中切除右子树(曾经的偏爱子节点)        root[ch[x][1] = y] = 0;        x = pre[y = x];    }    return y;}int findroot(int x) {    Access(x);    Splay(x);    while (ch[x][0]) x = ch[x][0];    Splay(x);    return x;}void cut(int v) {    Access(v);    Splay(v);    pre[ch[v][0]] = pre[v];    pre[v] = 0;    root[ch[v][0]] = 1;    ch[v][0] = 0;}void link(int u, int v) {    Access(v);    Splay(v);    pre[v] = u;}void Link(int u, int v) {    int rt = findroot(v);    if (rt == v) clr[rt] = 0;    else cut(v);    if (clr[rt] && findroot(clr[rt]) != rt) {        link(clr[rt], rt);        clr[rt] = 0;    }    if(u==0) return;    if (findroot(u) == v) clr[v] = u;    else link(u, v);}int main() {    //freopen("in.txt", "r", stdin);    while (~scanf("%d%d", &n, &m)) {        init();        for (int i = 1; i <= n; i++) scanf("%d", &a[i]);        for (int i = 1; i <= n; i++) if (a[i]) Link(a[i], i);        for (int i = 1; i <= m; i++) {            int op, x, y;            scanf("%d", &op);            if (op == 1) {                scanf("%d%d", &x, &y);                Link(y, x);            } else {                scanf("%d", &x);                x = findroot(x);                printf("%d\n", clr[x] ? -1 : x);            }        }    }    return 0;}