fzoj 2119 祖先问题

Problem 2119 祖先问题

Accept: 18    Submit: 82
Time Limit: 3000 mSec    Memory Limit : 32768 KB

 Problem Description

有n个结点构成了多棵树,给出每个结点的父节点,若为-1则表示该结点无父节点。每个结点的父节点编号必须比该结点的编号小。给m个操作,有两种操作:1.重新设置某结点的父节点;2.求某结点的祖先个数。一个结点的祖先为其父节点及其父节点的祖先。

 Input

有多组数据输入。每组数据的第一行为两个整数n,m。(1<=n,m<=200000)。第二行输入n个数,从1到n分别表示编号为1到n的结点的父节点,若为-1则表示该结点无父节点。接下来输入m行,表示m个操作,每行输入有两种:三个数t,a,b(t=0,1<= a <=n,b为-1或小于a的正整数),将结点a的父节点设置为b,若b为-1则表示将a设为无父节点;或者两个数t,a(t=1,1<=a<=n),表示询问结点a的祖先个数。数据保证每个结点的父节点编号比该结点小。所有输入都为整数。

 Output

对于每个询问输出一行一个整数,表示该结点的祖先数。

 Sample Input

4 3
-1 1 2 3
1 4
0 4 1
1 4

 Sample Output

3
1

 Source

FOJ有奖月赛-2013年4月(校赛热身赛)

思路:lct里面的access操作是把 自己到根的边置为重边,这样我们就可以直接用lct搞了

#pragma comment(linker,"/STACK:1024000000,1024000000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<set>
#include<stack>
#include<map>
#include<ctime>
#include<bitset>
#define LL long long
#define INF 0x3f3f3f3f
#define maxn 200010
#define eps 1e-6
#define mod 1000000007
using namespace std;

struct LCT
{
    int w[maxn],ff;
    int ch[maxn][2],pre[maxn] ;
    void init()
    {
        memset(ch,0,sizeof(ch)) ;
        memset(w,0,sizeof(w)) ;
        w[0]=0;
    }
    void update(int x )
    {
        w[x]=1+w[ch[x][1]]+w[ch[x][0]];
    }
    bool isroot(int x )
    {
        if(ch[pre[x]][0] != x && ch[pre[x]][1] != x )
            return true ;
        return false;
    }
    void rotate(int x,int f)
    {
        int y = pre[x],z = pre[y];
        ch[y][!f] = ch[x][f];
        pre[ ch[x][f] ] = y;
        pre[x] = pre[y];
        if(ch[z][0] == y)ch[z][0] = x;
        else if(ch[z][1] == y)ch[z][1] = x;
        pre[y] = x;
        ch[x][f] = y;
        update(y);
    }
    void splay(int x)
    {
        while(!isroot(x))
        {
            if(isroot(pre[x]))rotate(x,ch[pre[x]][0] == x);
            else
            {
                int y = pre[x],z = pre[y];
                int f = (ch[z][0] == y);
                if(ch[y][f] == x)rotate(x,!f),rotate(x,f);
                else rotate(y,f),rotate(x,f);
            }
        }
        update(x);
    }
    void access(int u)
    {
        int f;
        for(f = 0 ; u ;u = pre[u])
        {
            splay(u);
            ch[u][1] = f ;
            update(u);
            f = u ;
        }
        ff=f;
    }
    void cut(int x,int y )
    {
        access(y) ;
    }
    int find(int x)
    {
       access(x) ;
       splay(x);
       return w[x]-1;
    }
}lct;
int fa[maxn] ;
int main()
{
    int i , n ,m ,k ;
    int T,j ;
    while(scanf("%d%d",&n,&m) != EOF)
    {
        lct.init();
        for( i = 1 ; i <= n ;i++)
        {
            scanf("%d",&k) ;
            if(k==-1)
                lct.pre[i]=0,fa[i]=0;
            else lct.pre[i]=k,fa[i]=k;
        }
        while(m--)
        {
            scanf("%d",&k) ;
            if(k==1)
            {
                scanf("%d",&j) ;
                printf("%d\n",lct.find(j)) ;
            }
            else
            {
                scanf("%d%d",&i,&j) ;
                if(fa[i] != 0)
                  lct.cut(i,fa[i]) ;
                  lct.splay(i);
                if(j==-1)fa[i]=lct.pre[i]=0;
                else lct.pre[i]=j,fa[i]=j;
            }
        }
    }
    return 0 ;
}

时间: 2024-10-13 12:16:00

fzoj 2119 祖先问题的相关文章

1110 最近共同祖先

题目来源:https://acm.zzuli.edu.cn/zzuliacm/problem.php?id=1110Description 如上图所示,由正整数1, 2, 3, ...组成了一棵无限大的二叉树.从某一个结点到根结 点(编号是1 的结点)都有一条唯一的路径,比如从10 到根结点的路径是(10, 5, 2, 1), 从4 到根结点的路径是(4, 2, 1),从该结点到根结点的路径上的所有结点称为该结点的祖先.现在的问题就是,给定x 和y,求x和y的最近共同祖先,比如,10和4最近共同

【洛谷P3379】【模板】最近公共祖先(LCA)

题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每行包含两个正整数x.y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树). 接下来M行每行包含两个正整数a.b,表示询问a结点和b结点的最近公共祖先. 输出格式: 输出包含M行,每行包含一个正整数,依次为每一个询问的结果. 输入输出样例 输入样例#1: 5 5 4 3 1 2 4 5

50、树中两个节点的公共祖先

详细的询问: 1.该树是二叉查找树? 最近公共祖先----二叉查找树:(http://www.lintcode.com/problem/lowest-common-ancestor/) 思路:利用左子树特点:左子树 < 根 <= 右,输入节点跟根节点比较,都小于,在左子树,都大约右子树,递归的去遍历:找到当前节点在两个输入大小之间,当前节点就是. 递归和非递归 public class Solution { public TreeNode lowestCommonAncestor(TreeNo

[最近公共祖先] POJ 3728 The merchant

The merchant Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 4556   Accepted: 1576 Description There are N cities in a country, and there is one and only one simple path between each pair of cities. A merchant has chosen some paths and w

lca最近公共祖先(st表)

大体思路 1.求出每个元素在树中的深度 2.用st表预处理的方法处理出f[i][j],f[i][j]表示元素i上方第2^j行对应的祖先是谁 3.将较深的点向上挪,直到两结点的深度相同 4.深度相同后,祖先可能就在上方,再走几步就到了,于是两个点同时向上移 具体的方法和代码贴在下面 ↓ 具体来看 1.求出每个元素在树中的深度 //求每个节点在树中的深度 void dfs(int pos,int pre)//pre是pos的父节点 { for(int i=0;i<v[pos].size;i++)//

hihoCoder#1062(最近公共祖先一)

时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Ho最近发现了一个神奇的网站!虽然还不够像58同城那样神奇,但这个网站仍然让小Ho乐在其中,但这是为什么呢? “为什么呢?”小Hi如是问道,在他的观察中小Ho已经沉迷这个网站一周之久了,甚至连他心爱的树玩具都弃置一边. “嘿嘿,小Hi,你快过来看!”小Ho招呼道. “你看,在这个对话框里输入我的名字,在另一个对话框里,输入你的名字,再点这个查询按钮,就可以查出来……什么!我们居然有同一个祖祖祖祖祖爷爷?” “诶,真是

LCA(最近公共祖先)--tarjan离线算法 hdu 2586

HDU 2586 How far away ? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 11320    Accepted Submission(s): 4119 Problem Description There are n houses in the village and some bidirectional roads c

最近公共祖先 LCA Tarjan算法

来自:http://www.cnblogs.com/ylfdrib/archive/2010/11/03/1867901.html 对于一棵有根树,就会有父亲结点,祖先结点,当然最近公共祖先就是这两个点所有的祖先结点中深度最大的一个结点. 0 | 1 /   \ 2      3 比如说在这里,如果0为根的话,那么1是2和3的父亲结点,0是1的父亲结点,0和1都是2和3的公共祖先结点,但是1才是最近的公共祖先结点,或者说1是2和3的所有祖先结点中距离根结点最远的祖先结点. 在求解最近公共祖先为问

访问祖先类的虚方法(直接访问祖先类的VMT,但是这种方法在新版本中未必可靠)

访问祖先类的虚方法 问题提出 在子类覆盖的虚方法中,可以用inherited调用父类的实现,但有时候我们并不需要父类的实现,而是想跃过父类直接调用祖先类的方法. 举个例子,假设有三个类,实现如下: type TClassA = class procedure Proc; virtual; end; TClassB = class(TClassA) procedure Proc; override; end; TClassC = class(TClassB) procedure Proc; ove