HDU 3078 (LCA+树链第K大)

题目链接http://acm.hdu.edu.cn/showproblem.php?pid=3078

题目大意:定点修改。查询树中任意一条树链上,第K大值。

解题思路

先用离线Tarjan把每个Query树链的LCA求出来。

LCA中对连接树Dfs的时候,令p[v]=u,记录v的前驱。

LCA结束后,对于每个Query:

从u开始回溯到LCA,记录值。从v开始回溯到LCA,记录值。

再加上LCA这个点的值,形成一条完整树链。特判树链长度是否小于K。

对树链中的值,从大到小排序,取第K大即可。

#include "cstdio"
#include "cstring"
#include "vector"
#include "algorithm"
using namespace std;
#define maxn 80005
int head[maxn],qhead[maxn],lag[maxn],kth[maxn],tot1,tot2,f[maxn],vis[maxn],ancestor[maxn],p[maxn];
bool cmp(int a,int b) {return a>b;}
struct Edge
{
    int to,next;
}e[maxn*2];
struct Query
{
    int from,to,next,idx;
}q[maxn*2];
void addedge(int u,int v)
{
    e[tot1].to=v;
    e[tot1].next=head[u];
    head[u]=tot1++;
}
void addquery(int u,int v,int idx)
{
    q[tot2].from=u;
    q[tot2].to=v;
    q[tot2].next=qhead[u];
    q[tot2].idx=idx;
    qhead[u]=tot2++;
}
int find(int x) {return x!=f[x]?f[x]=find(f[x]):x;}
void Union(int u,int v)
{
    u=find(u),v=find(v);
    if(u!=v) f[v]=u;
}
void LCA(int u)
{
    vis[u]=true;
    f[u]=u;
    for(int i=head[u];i!=-1;i=e[i].next)
    {
        int v=e[i].to;
        if(!vis[v])
        {
            p[v]=u;
            LCA(v);
            Union(u,v);
        }
    }
    for(int i=qhead[u];i!=-1;i=q[i].next)
    {
        int v=q[i].to;
        if(vis[v]) ancestor[q[i].idx]=find(v);
        //or storage e[i].lca=e[i^1].lca=find(v)
    }
}
int main()
{
    //freopen("in.txt","r",stdin);
    int T,n,m,u,v,c,cmd;
    scanf("%d%d",&n,&m);
    tot1=tot2=0;
    memset(head,-1,sizeof(head));
    memset(qhead,-1,sizeof(qhead));
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=n;i++) scanf("%d",&lag[i]);
    for(int i=0; i<n-1; i++)
    {
        scanf("%d%d",&u,&v);
        addedge(u,v);
        addedge(v,u);
    }
    for(int i=0; i<m; i++)
    {
        scanf("%d%d%d",&cmd,&u,&v);
        if(cmd==0) lag[u]=v;
        else
        {
            addquery(u,v,i);
            addquery(v,u,i);
            kth[i]=cmd;
        }
    }
    LCA(1);
    for(int i=0; i<tot2; i=i+2)
    {
        int u=q[i].from,v=q[i].to,idx=q[i].idx;
        int ed=ancestor[idx];
        vector<int> chain;
        while(u!=ed) chain.push_back(lag[u]),u=p[u];
        while(v!=ed) chain.push_back(lag[v]),v=p[v];
        chain.push_back(lag[ed]);
        if(chain.size()<kth[idx]) {printf("invalid request!\n");continue;}
        else
        {
            sort(chain.begin(),chain.end(),cmp);
            printf("%d\n",chain[kth[idx]-1]);
        }
    }
}
时间: 2024-11-05 18:45:47

HDU 3078 (LCA+树链第K大)的相关文章

HDU 6278 主席树(区间第k大)+二分

Just h-index Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Others)Total Submission(s): 438    Accepted Submission(s): 203 Problem Description The h-index of an author is the largest h where he has at least h papers wit

hdu 5458 Stability(树链剖分+并查集)

Stability Time Limit: 3000/2000 MS (Java/Others)    Memory Limit: 65535/102400 K (Java/Others)Total Submission(s): 1347    Accepted Submission(s): 319 Problem Description Given an undirected connected graph G with n nodes and m edges, with possibly r

Count on a tree SPOJ 主席树+LCA(树链剖分实现)(两种存图方式)

Count on a tree SPOJ 主席树+LCA(树链剖分实现)(两种存图方式) 题外话,这是我第40篇随笔,纪念一下.<( ̄︶ ̄)[GO!] 题意 是说有棵树,每个节点上都有一个值,然后让你求从一个节点到另一个节点的最短路上第k小的值是多少. 解题思路 看到这个题一想以为是树链剖分+主席树,后来写着写着发现不对,因为树链剖分我们分成了一小段一小段,这些小段不能合并起来求第k小,所以这个想法不对.奈何不会做,查了查题解,需要用LCA(最近公共祖先),然后根据主席树具有区间加减的性质,我们

HDU 1031 Design T-Shirt 选前k大

相当于给出一组数列,然后选择前K大的数的算法. 本题没有给出详细的数据,故此就使用动态分配空间的方法了. 而这种题最好的算法就是使用快排思想,期望时间效率就是O(n)了. 最基本入门解决这种题的算法是直接排序了.那就成了水代码了.用上快排的思想才能体现出水平. 不过这种快排实在考的太多了,建议一定要掌握. 每次做这个算法的题目总会要调试一定时间的,每次都出现奇葩的错误.看来还是不够细心. 做题的时候一定要排除杂念,有干扰,后果很严重,会花长很多时间. 靖空间做题,一定要静,达到一种禅的境界.说禅

zoj 2112 Dynamic Rankings(主席树&amp;动态第k大)

Dynamic Rankings Time Limit: 10 Seconds      Memory Limit: 32768 KB The Company Dynamic Rankings has developed a new kind of computer that is no longer satisfied with the query like to simply find the k-th smallest number of the given N numbers. They

HDU 3966 RE 树链剖分 Aragorn&#39;s Story

给一棵点带权的图 有这样一个操作: 使树上某一条路径所有点权值增减 每次询问某个点现在的权值. 树链剖分完以后,就是线段树的成段更新了. 这题感觉A不了了,无限RE,手动开栈也没卵用. 还是把我辛辛苦苦写的代码贴一下吧. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <vector> 6 using

LCA 树链剖分

//LCA //树链剖分 在线 #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> using namespace std; int n,m,root,cnt,head[500001]; int hvyson[500001],fa[500001],siz[500001],d

UOJ#53. 【UR #4】追击圣诞老人 树链剖分 k短路

原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ53.html 题意 给定一棵有 n 个节点的树. 每一个点有一个权值. 对于每一个 $i$ 给定三个参数 $a_i,b_i,c_i$ ,从第 $i$ 个点出发下一步能到达的点 x 需要满足以下三个要求之一: 1. x 在 $a_i$ 到 $b_i$ 的简单路径上. 2. x 在 $a_i$ 到 $c_i$ 的简单路径上. 3. x 在 $c_i$ 到 $b_i$ 的简单路径上. 问从任意一个点出发,经过

hdu 3078(LCA的在线算法)

Network Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 847    Accepted Submission(s): 347 Problem Description The ALPC company is now working on his own network system, which is connecting all