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

题意:给出一棵树,每个节点有一个权值。两种操作:(1) 修改某个节点的权值;(2)询问a到b路径上第K大的权值。

思路:首先,DFS两次得到树链(重新标号,一个树链上的节点的标号连续)。建立线段树,再为线段树每个节点建立一棵BST。(1)修改时,在线段树上依次向下修改,并且到达每个节点时要修改相应的BST,即删掉原来的权值,插入新的权值,复杂度(logn)^2;(2)查询:转化成区间第K小的。计算出(a,b)的最近公共祖先lca。二分答案x,在路径(a,lca)和(b,lca)上分别计算小于等于x的节点个数。比如计算(a,lca),就是顺着a所在树链依次向上,最多有logn个树链,然后在每个树链上查找,其实就是在线段树上查找,整个复杂度是(logn)^3。

vector<int> g[N];
int leaf[N],f[N][20],size[N],a[N],id[N],wh[N];
int visit[N],dep[N],head[N];
int T;

void dfs(int u)
{
    visit[u]=1; size[u]=1;
    int i,v;
    FOR0(i,SZ(g[u]))
    {
        v=g[u][i];
        if(visit[v]) continue;
        f[v][0]=u;
        dep[v]=dep[u]+1;
        dfs(v);
        size[u]+=size[v];
    }
    if(size[u]==1) leaf[u]=1;
}

void DFS(int u,int top)
{
    head[u]=top; id[++T]=u; wh[u]=T;
    if(leaf[u]) return;
    
    int maxSon,Max=-1;
    int i,v;
    FOR0(i,SZ(g[u]))
    {
        v=g[u][i];
        if(v==f[u][0]) continue;
        if(size[v]>Max) Max=size[v],maxSon=v;
    }
    DFS(maxSon,top);
    FOR0(i,SZ(g[u]))
    {
        v=g[u][i];
        if(v!=maxSon&&v!=f[u][0]) DFS(v,v);
    }
}

int n,m;

void init()
{
    RD(n,m);
    int i,x,y;
    FOR1(i,n) RD(a[i]);
    FOR1(i,n-1)
    {
        RD(x,y);
        g[x].pb(y);
        g[y].pb(x);
    }
    dfs(1); DFS(1,1);
    int j;
    for(i=1;(1<<i)<=n;i++)
    {
        for(j=1;j<=n;j++) f[j][i]=f[f[j][i-1]][i-1];
    }
}

int getLca(int x,int y)
{
    if(x==y) return x;
    if(dep[x]>dep[y]) swap(x,y);
    int t=dep[y]-dep[x],i;
    for(i=0;i<20;i++) if(t&(1<<i))
    {
        y=f[y][i];
    }
    if(x==y) return x;
    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];
}

struct node
{
    int L,R,size,cnt,key;
};

struct Node
{
    int L,R,root;
};

node tree[N<<5];
Node segTree[N<<2];
int e;

int newNode(int key)
{
    e++;
    tree[e].key=key;
    tree[e].L=tree[e].R=0;
    tree[e].cnt=1;
    tree[e].size=1;
    return e;
}

void insert(int x,int key)
{
    int p=x;
    while(1)
    {
        tree[p].size++;
        if(tree[p].key==key)
        {
            tree[p].cnt++;
            return;
        }
        if(tree[p].key<key)
        {
            if(tree[p].R==0)
            {
                tree[p].R=newNode(key);
                return;
            }
            else p=tree[p].R;
        }
        else
        {
            if(tree[p].L==0)
            {
                tree[p].L=newNode(key);
                return;
            }
            else p=tree[p].L;
        }
    }
}

void build(int t,int L,int R)
{
    segTree[t].L=L;
    segTree[t].R=R;
    segTree[t].root=newNode(a[id[L]]);
    if(L==R) return;
    int mid=(L+R)>>1;
    build(t*2,L,mid);
    build(t*2+1,mid+1,R);
    int i;
    for(i=L+1;i<=R;i++) insert(segTree[t].root,a[id[i]]);
}

void del(int x,int key)
{
    int p=x;
    while(1)
    {
        tree[p].size--;
        if(tree[p].key==key)
        {
            tree[p].cnt--;
            return;
        }
        if(key<tree[p].key) p=tree[p].L;
        else p=tree[p].R;
    }
}

void modify(int t,int pos,int x,int y)
{
    del(segTree[t].root,x);
    insert(segTree[t].root,y);
    if(segTree[t].L==segTree[t].R) return;
    int mid=(segTree[t].L+segTree[t].R)>>1;
    if(pos<=mid) modify(t*2,pos,x,y);
    else modify(t*2+1,pos,x,y);
}

int cal(int x,int key)
{
    int ans=0,p=x;
    while(p)
    {
        if(key==tree[p].key)
        {
            ans+=tree[p].size-tree[tree[p].R].size;
            return ans;
        }
        if(key<tree[p].key) p=tree[p].L;
        else
        {
            ans+=tree[p].size-tree[tree[p].R].size;
            p=tree[p].R;
        }
    }
    return ans;
}

int query(int t,int L,int R,int key)
{
    if(segTree[t].L==L&&segTree[t].R==R)
    {
        return cal(segTree[t].root,key);
    }
    int mid=(segTree[t].L+segTree[t].R)>>1;
    if(R<=mid) return query(t*2,L,R,key);
    if(L>mid) return query(t*2+1,L,R,key);
    return query(t*2,L,mid,key)+query(t*2+1,mid+1,R,key);
}

int query(int L,int R,int key)
{
    int ans=0;
    while(head[L]!=head[R])
    {
        ans+=query(1,wh[head[L]],wh[L],key);
        L=f[head[L]][0];
    }
    ans+=query(1,wh[R],wh[L],key);
    return ans;
}

int calKth(int x,int y,int lca,int K)
{
    int low=0,high=INF,mid,ans,cnt;
    while(low<=high)
    {
        mid=(low+high)>>1;
        cnt=query(x,lca,mid)+query(y,lca,mid);
        if(a[lca]<=mid) cnt--;
        if(cnt>=K) ans=mid,high=mid-1;
        else low=mid+1;
    }
    return ans;
}

int main()
{
    init(); build(1,1,n);
    int op,x,y,lca,cnt;
    while(m--)
    {
        RD(op); RD(x,y);
        if(op==0) modify(1,wh[x],a[x],y),a[x]=y;
        else 
        {
            lca=getLca(x,y);
            cnt=dep[x]+dep[y]-dep[lca]*2+1;
            if(cnt<op) puts("invalid request!");
            else PR(calKth(x,y,lca,cnt-op+1));
        }
    }
}

BZOJ 1146 网络管理Network(树链剖分+BST)相关推荐

  1. BZOJ 1146: [CTSC2008]网络管理Network( 树链剖分 + 树状数组套主席树 )

    树链剖分完就成了一道主席树裸题了, 每次树链剖分找出相应区间然后用BIT+(可持久化)权值线段树就可以完成计数. 但是空间问题很严重....在修改时不必要的就不要新建, 直接修改原来的..详见代码. ...

  2. BZOJ1146 [CTSC2008]网络管理Network 树链剖分 主席树 树状数组

    欢迎访问~原文出处--博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1146 题意概括 在一棵树上,每一个点一个权值. 有两种操作: 1.单点修改 2.询问两点之间的树链 ...

  3. BZOJ 2243 染色(树链剖分好题)

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MB Submit: 7971  Solved: 2990 [Submit][Stat ...

  4. BZOJ 4034 [HAOI2015]T2 树链剖分

    Description 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中 ...

  5. BZOJ 4034: [HAOI2015]T2 树链剖分

    4034: [HAOI2015]T2 Description 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操 ...

  6. bzoj 4127: Abs(树链剖分+线段树)

    4127: Abs Time Limit: 40 Sec  Memory Limit: 256 MB Submit: 667  Solved: 225 [Submit][Status][Discuss ...

  7. 【bzoj1146】 [CTSC2008]网络管理Network【树链剖分+树套树+二分 线段树套Treap】

    1146: [CTSC2008]网络管理Network Description M公司是一个非常庞大的跨国公司,在许多国家都设有它的下属分支机构或部门.为了让分布在世界各地的N个 部门之间协同工作,公 ...

  8. BZOJ 2157 「国家集训队」旅游(树链剖分,线段树,边权转点权)【BZOJ计划】

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 题目链接 https://hydro.ac/d/bzoj/p/2157 是 hydro 的 BZOJ ...

  9. BZOJ 2402 陶陶的难题II (树链剖分、线段树、凸包、分数规划)

    毒瘤,毒瘤,毒瘤-- \(30000\)这个数据范围,看上去就是要搞事的啊... 题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=2402 ...

  10. HDU 2460 Network(双连通+树链剖分+线段树)

    HDU 2460 Network 题目链接 题意:给定一个无向图,问每次增加一条边,问个图中还剩多少桥 思路:先双连通缩点,然后形成一棵树,每次增加一条边,相当于询问这两点路径上有多少条边,这个用树链 ...

最新文章

  1. 空间金字塔方法表示图像
  2. 【模板】最小割树(Gomory-Hu Tree)
  3. kill session-KILL_SESSION()
  4. Linux/Windows/MacOS各个操作系统下推荐应用集合
  5. Consecutive Sum LightOJ - 1269(区间异或和)
  6. 微软软件推送服务器,微软将通过系统更新功能向大部分用户推送新版Microsoft Edge浏览器-...
  7. 解决Jenkins上git出现的“ERROR: Error fetching remote repo ‘origin‘”问题
  8. 摩拜服务器维护,摩拜的后台是云服务器
  9. MPU6050 六轴传感器实验
  10. QT修改releas发布的exe图标
  11. 和计算机相关的祝福语,祝福语精选
  12. 数字人还能设计数字藏品?希加加xQee创作人间十二月
  13. vue element-ui 键盘输入enter键 触发事件
  14. python的round函数使用
  15. 交换机(三层)接入层、汇聚层和核心层交换机的特点
  16. 加班、加人、延期是糟糕的办法
  17. 手机微信中对方正在输入...,不显示有4种原因,还能永不显示
  18. SpringSecurity 安全框架
  19. 见微知著,从小需求里看产品的抉择和定位
  20. 安装测试包(.ipa)到iPhone手机

热门文章

  1. Atitit 遗留系统的改造 微创技术 attilax总结 目录 1. 微创是高科技带来的革命! 1 1.1. 早期微创 1 1.2. 微创五大优点 1 2. 常用辅助设备与模块 2 2.1. 清晰
  2. Atitit 让maven pom.xml不编译 1.build   2.  defaultGoalinstall/defaultGoal   3.  directory${bas
  3. paip.互联网产品要成功的要素
  4. AJAX在IE下的调试
  5. 从毫无交集到走向融合,AI+区块链才是改变世界的黑科技!
  6. 一个空格引发的Bug! ----CSV输出和CSV读入
  7. 【精品分享】Kolla 让 OpenStack 部署更贴心
  8. 英特尔王庆连续四年担任OpenStack基金会个人独立董事
  9. 计算机技巧网站,13个实用电脑技巧汇总
  10. 如何更新计算机的flash player,如何在win7电脑中Adobe Flash Player自动更新?