UVALive - 7831 :ACM Tax (主席树求树路径上中位数:LCA+主席树)

题意:给定一棵带权树,Q次询问,每次询问路径上的中位数。

思路:中位数分边数奇偶考虑,当当边数为num=奇时,结果就算路径第num/2+1大,用主席树做即可。。。

(做了几道比较难的主席树,都wa了。。。只有来刷刷水题,准备晚上的CF了)

#include<bits/stdc++.h>
using namespace std;
const int maxn=1000010;
int Laxt[maxn],Next[maxn],To[maxn],cost[maxn],cnt;
int fa[50010][20],dep[maxn],rt[maxn],tot;
struct in{ int l,r,sum; }s[maxn];
void init()
{
    cnt=0; tot=0;
    memset(Laxt,0,sizeof(Laxt));
    memset(s,0,sizeof(s));
    memset(rt,0,sizeof(rt));
}
void add(int u,int v,int c){Next[++cnt]=Laxt[u];Laxt[u]=cnt;To[cnt]=v;cost[cnt]=c;}
void Add(int &Now,int pre,int L,int R,int pos)
{
    Now=++tot; s[Now]=s[pre]; s[Now].sum++;
    if(L==R) return ; int Mid=(L+R)>>1;
    if(pos<=Mid) Add(s[Now].l,s[pre].l,L,Mid,pos);
    else Add(s[Now].r,s[pre].r,Mid+1,R,pos);
}
int query(int Now1,int Now2,int pre,int L,int R,int K)
{
    if(L==R) return L; int Mid=(L+R)>>1;
    int tmp=s[s[Now1].l].sum+s[s[Now2].l].sum-2*s[s[pre].l].sum;
    if(tmp>=K) return query(s[Now1].l,s[Now2].l,s[pre].l,L,Mid,K);
    else return query(s[Now1].r,s[Now2].r,s[pre].r,Mid+1,R,K-tmp);
}
void dfs(int u,int f)
{
    dep[u]=dep[f]+1; fa[u][0]=f;
    for(int i=Laxt[u];i;i=Next[i])
    if(To[i]!=f) {
        Add(rt[To[i]],rt[u],1,100000,cost[i]);
        dfs(To[i],u);
    }
}
int LCA(int u,int v)
{
    if(dep[u]<dep[v]) swap(u,v);
    for(int i=19;i>=0;i--) if(dep[fa[u][i]]>=dep[v]) u=fa[u][i];
    if(u==v) return u;
    for(int i=19;i>=0;i--) if(fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i];
    return fa[u][0];
}
int main()
{
    int T,N,Q,x,y,c,i,j;
    scanf("%d",&T);
    while(T--){
        init();
        scanf("%d",&N);
        for(i=1;i<N;i++){
            scanf("%d%d%d",&x,&y,&c);
            add(x,y,c); add(y,x,c);
        }
        dfs(1,0);
        for(i=1;i<20;i++)
         for(j=1;j<=N;j++)
          fa[j][i]=fa[fa[j][i-1]][i-1];
        scanf("%d",&Q);
        while(Q--){
            scanf("%d%d",&x,&y);
            int Lca=LCA(x,y);
            int num=dep[x]-dep[Lca]+dep[y]-dep[Lca];
            if(num%2==0){
                double aa=query(rt[x],rt[y],rt[Lca],1,100000,num/2);
                double bb=query(rt[x],rt[y],rt[Lca],1,100000,num/2+1);
                printf("%.1lf\n",(aa+bb)/2);
            }
            else {
                double ans=query(rt[x],rt[y],rt[Lca],1,100000,num/2+1);
                printf("%.1lf\n",ans);
            }
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/hua-dong/p/9222326.html

时间: 2024-08-10 17:18:10

UVALive - 7831 :ACM Tax (主席树求树路径上中位数:LCA+主席树)的相关文章

LCA+主席树 (求树上路径点权第k大)

SPOJ 10628. Count on a tree (树上第k大,LCA+主席树) 10628. Count on a tree Problem code: COT You are given a tree with N nodes.The tree nodes are numbered from 1 to N.Each node has an integer weight. We will ask you to perform the following operation: u v k 

hdu 2665 可持久化线段树求区间第K大值(函数式线段树||主席树)

http://acm.hdu.edu.cn/showproblem.php?pid=2665 Problem Description Give you a sequence and ask you the kth big number of a inteval. Input The first line is the number of the test cases. For each test case, the first line contain two integer n and m (

POJ 2104 求序列里第K大 主席树裸体题

给定一个n的序列,有m个询问 每次询问求l-r 里面第k大的数字是什么 只有询问,没有修改 可以用归并树和划分树(我都没学过..囧) 我是专门冲着弄主席树来的 对主席树的建树方式有点了解了,不过这题为什么是在主席树里面这么操作的 还是有点不懂,今天照着模板敲了一遍就打多校了 再研究吧 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using name

SPOJ 10628 Count on a tree(Tarjan离线LCA+主席树求树上第K小)

COT - Count on a tree #tree You are given a tree with N nodes.The tree nodes are numbered from 1 to N.Each node has an integer weight. We will ask you to perform the following operation: u v k : ask for the kth minimum weight on the path from node u 

HDU 4911 http://acm.hdu.edu.cn/showproblem.php?pid=4911(线段树求逆序对)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4911 解题报告: 给出一个长度为n的序列,然后给出一个k,要你求最多做k次相邻的数字交换后,逆序数最少是多少? 因为每次相邻的交换操作最多只能减少一个逆序对,所以最多可以减少k个逆序对,所以我们只要求出原来的序列有多少个逆序对然后减去k再跟0取较大的就可以了. 因为数据范围是10的五次方,所以暴力求肯定会TLE,所以要用n*logn算法求逆序对,n*logn算法有几种可以求逆序对的: 线段树,树状数

杭电 1754 I Hate It(线段树求最值)

http://acm.hdu.edu.cn/showproblem.php?pid=1754 I Hate It Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 38601    Accepted Submission(s): 15270 Problem Description 很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某

2016年湖南省第十二届大学生计算机程序设计竞赛---Parenthesis(线段树求区间最值)

原题链接 http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1809 Description Bobo has a balanced parenthesis sequence P=p1 p2…pn of length n and q questions. The i-th question is whether P remains balanced after pai and pbi  swapped. Note that questions ar

UVA - 11983 Weird Advertisement (线段树求并面积)

Description G Weird Advertisement Renat Mullakhanov (rem), one of the most talented programmers in the world, passed away on March 11, 2011. This is very sad news for all of us. His team went to ACM ICPC World Finals - 2004, placed 4th and won gold m

BNU 2418 Ultra-QuickSort (线段树求逆序对)

题目链接:http://acm.bnu.edu.cn/bnuoj/problem_show.php?pid=2418 解题报告:就是给你n个数,然后让你求这个数列的逆序对是多少?题目中n的范围是n < 500000,所以,暴力是不行的.还是第一次学会用线段树求逆序数,这种方法的时间复杂度是n * log n,是不是很快呢,利用了线段树查询速度快的优势.具体的方法如下: 这里先说一下,如果输入的n个数不是连续的,也就是说把这n个数按从小到大的顺序排列起来不是连续的话,还要先离散化一下,其实也就是把