题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=3123

题意:

思路:总的来说,查询区间第K小利用函数式线段树的减法操作。对于两棵树的合并,将节点少的树暴力插入到节点大的树上面。对于本题,首先,将输入的权值离散化,为已经给出的边建立函数式线段树。对于合并x,y,将y的父节点设为x,然后重新建立y为根的子树的函数式线段树。对于查询x,y,k,设其LCA为p,p的父节点为q,则x+y-p-q就是整个区间。


struct node
{
    int L,R,s;
};

node tree[N*400];
int root[N],tot;
int f[N][20],w[N],n,m,K,d[N],size[N];
vector<int> g[N];
int M;
int b[N];

int build(int a,int b)
{
    int k=++tot;
    tree[k].s=0;
    if(a==b) return k;
    int mid=(a+b)>>1;
    tree[k].L=build(a,mid);
    tree[k].R=build(mid+1,b);
    return k;
}

int insert(int c,int s,int a,int b)
{
    int k=++tot;
    tree[k]=tree[c];
    tree[k].s++;
    if(a==b) return k;
    int mid=(a+b)>>1;
    if(s<=mid) tree[k].L=insert(tree[c].L,s,a,mid);
    else tree[k].R=insert(tree[c].R,s,mid+1,b);
    return k;
}

int visit[N],X;

void BFS(int u)
{
    queue<int> Q;
    Q.push(u);
    int i,v;
    while(!Q.empty())
    {
        u=Q.front();
        Q.pop();
        visit[u]=X;
        root[u]=insert(root[f[u][0]],w[u],0,M);
        for(i=1;i<20;i++) f[u][i]=f[f[u][i-1]][i-1];
        FOR0(i,SZ(g[u]))
        {
            v=g[u][i];
            if(visit[v]==X) continue;
            f[v][0]=u;
            d[v]=d[u]+1;
            Q.push(v);
        }
    }
}

int get(int x,int k)
{
    int i;
    FOR0(i,20) if(k&(1<<i)) x=f[x][i];
    return x;
}

int getLca(int x,int y)
{
    if(d[x]>d[y]) swap(x,y);
    y=get(y,d[y]-d[x]);
    if(x==y) return x;
    int i;
    for(i=19;i>=0;i--) if(f[x][i]&&f[y][i]&&f[x][i]!=f[y][i])
    {
        x=f[x][i];
        y=f[y][i];
    }
    return f[x][0];
}

#define L(a) tree[tree[a].L].s

int query(int a,int b,int c,int d,int k,int L,int R)
{
    if(L==R) return L;
    int s=L(a)+L(b)-L(c)-L(d);
    int mid=(L+R)>>1;
    if(k<=s) return query(tree[a].L,tree[b].L,tree[c].L,tree[d].L,k,L,mid);
    return query(tree[a].R,tree[b].R,tree[c].R,tree[d].R,k-s,mid+1,R);
}

void go()
{
    int x,y,k,p,last=0;
    char op[10];
    int fx,fy;
    while(K--)
    {
        RD(op);
        if(op[0]=='Q')
        {
            RD(x,y,k);
            x^=last; y^=last; k^=last;
            p=getLca(x,y);
            last=b[query(root[x],root[y],root[p],root[f[p][0]],k,0,M)];
            PR(last);
        }
        else
        {
            RD(x,y);
            x^=last; y^=last;
            fx=get(x,d[x]);
            fy=get(y,d[y]);
            g[x].pb(y);
            g[y].pb(x);
            X++;
            if(size[fx]>=size[fy])
            {
                size[fx]+=size[fy];
                f[y][0]=x;
                d[y]=d[x]+1;
                visit[x]=X;
                BFS(y);
            }
            else
            {
                size[fy]+=size[fx];
                f[x][0]=y;
                d[x]=d[y]+1;
                visit[y]=X;
                BFS(x);
            }
        }
    }
}

int main()
{
    int CC;
    RD(CC);
    RD(n,m,K);
    int i,j,u,v;
    FOR1(i,n) RD(w[i]),size[i]=1,b[i]=w[i];
    sort(b+1,b+n+1);
    M=unique(b+1,b+n+1)-(b+1);
    FOR1(i,n) w[i]=lower_bound(b+1,b+M+1,w[i])-b;
    tot=0;
    root[0]=build(0,M);
    FOR1(i,m)
    {
        RD(u,v);
        g[u].pb(v);
        g[v].pb(u);
    }
    FOR1(i,n) f[i][0]=-1;
    FOR1(i,n) if(f[i][0]==-1)
    {
        f[i][0]=0; d[i]=0; X++;
        BFS(i);
    }
    go();
}

  

BZOJ 3123 森林(函数式线段树)的更多相关文章

  1. bzoj 3123 可持久化线段树启发式合并

    首先没有连边的操作的时候,我们可以用可持久化线段树来维护这棵树的信息,建立权值可持久化线段树,那么每个点继承父节点的线段树,当询问为x,y的时候我们可以询问rot[x]+rot[y]-rot[lca( ...

  2. BZOJ 3207 花神的嘲讽计划Ⅰ(函数式线段树)

    题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=3207 题意:给出一个数列,若干询问.每个询问查询[L,R]区间内是否存在某个长度为K的子 ...

  3. 学习笔记--函数式线段树(主席树)(动态维护第K极值(树状数组套主席树))

    函数式线段树..资瓷 区间第K极值查询 似乎不过似乎划分树的效率更优于它,但是如果主席树套树状数组后,可以处理动态的第K极值.即资瓷插入删除,划分树则不同- 那么原理也比较易懂: 建造一棵线段树(权值 ...

  4. POJ2104 K-th number 函数式线段树

    很久没打代码了,不知道为什么,昨天考岭南文化之前突然开始思考起这个问题来,这个问题据说有很多种方法,划分树什么的,不过对于我现在这种水平还是用熟悉的线段树做比较好.这到题今年8月份的时候曾经做过,那个 ...

  5. [Usaco2014 Open Gold ]Cow Optics (树状数组+扫描线/函数式线段树)

    这道题一上手就知道怎么做了= = 直接求出原光路和从目标点出发的光路,求这些光路的交点就行了 然后用树状数组+扫描线或函数式线段树就能过了= = 大量的离散+模拟+二分什么的特别恶心,考试的时候是想到 ...

  6. hdu 5111 树链剖分加函数式线段树

    这题说的是给了两棵树,各有100000 个节点,然后Q个操作Q<=50000; 每个操作L1 R1 L2 R2.因为对于每棵树都有一个与本棵树其他点与众不同的值, 最后问 在树上从L1到R1这条 ...

  7. Codeforces538F A Heap of Heaps(函数式线段树)

    题意:给你一个数组a[n],对于数组每次建立一个完全k叉树,对于每个节点,如果父节点的值比这个节点的值大,那么就是一个违规点,统计出1~n-1完全叉树下的违规点的各自的个数. 一个直觉的思想就是暴力, ...

  8. Bzoj 2752 高速公路 (期望,线段树)

    Bzoj 2752 高速公路 (期望,线段树) 题目链接 这道题显然求边,因为题目是一条链,所以直接采用把边编上号.看成序列即可 \(1\)与\(2\)号点的边连得是. 编号为\(1\)的点.查询的时 ...

  9. BZOJ - 3123 森林 (可持久化线段树+启发式合并)

    题目链接 先把初始边建成一个森林,每棵树选一个根节点递归建可持久化线段树.当添加新边的时候,把结点数少的树暴力重构,以和它连边的那个点作为父节点继承线段树,并求出倍增数组.树的结点数可以用并查集来维护 ...

随机推荐

  1. CSS3实战之新增的选择器

    用的比较少 看到知道怎么回事就ok http://www.w3.org/TR/css3-selectors/#selectors http://www.cnblogs.com/jscode/archi ...

  2. NGUI基础之button(按钮)

    1,button的创建:2,button组件的基本属性:3,button的事件监听 原位地址:http://blog.csdn.net/dingkun520wy/article/details/504 ...

  3. github客户端创建仓库

    1.在github上创建立自己项目仓库 登录后,在github首页,点击页面右下角“New Repository” 填写项目信息: project name: project description  ...

  4. JDBC 学习笔记(四)—— 自定义JDBC框架+Apache—DBUtils框架+事务管理+操作多表

    本文目录:       1.自定义JDBC框架 ——数据库元数据:DataBaseMetaData        2.自定义JDBC框架 ——数据库元数据:DataBaseMetaData       ...

  5. 复习linq

    复习linq linq的英文是language integrated query.其中query的意思就是疑问或者计算机用语就是从资料库中提取信息的要求,可以理解为查询的意思.那么它翻译过来的话就是集 ...

  6. ADT通过svn进行团队开发,svn插件不好使的解决方案

    在使用ADT的svn插件的时候老是会出现各种异常,所以就干脆不用svn插件了,直接将adt的工作空间建在svn上面,以保证团队成员共用一套代码,节约宝贵的整合时间. 使用步骤: 1.首先需要安装好sv ...

  7. 【UVA】【11021】麻球繁衍

    数序期望 刘汝佳老师的白书上的例题……参见白书 //UVA 11021 #include<cmath> #include<cstdio> #define rep(i,n) fo ...

  8. Windows Server 2008下共享资源访问走捷径 (不用用户名 和 密码 访问共享)

    1. 启用来宾帐号2. 共享目录添加“Guest”帐号3. “gpedit.msc”,打开对应系统的组策略编辑窗口;在该编辑窗口的左侧显示区域,依次展开“本地计算机策略”/“计算机配置”/“Windo ...

  9. [设计模式] 8 组合模式 Composite

    DP书上给出的定义:将对象组合成树形结构以表示“部分-整体”的层次结构.组合使得用户对单个对象和组合对象的使用具有一致性.注意两个字“树形”.这种树形结构在现实生活中随处可见,比如一个集团公司,它有一 ...

  10. SPOJ 3693 Maximum Sum(水题,记录区间第一大和第二大数)

    #include <iostream> #include <stdio.h> #include <algorithm> #define lson rt<< ...