COJ966 WZJ的数据结构(负三十四)

WZJ的数据结构(负三十四)
难度级别:C; 运行时间限制:20000ms; 运行空间限制:262144KB; 代码长度限制:2000000B

试题描述

给一棵n个节点的树,请对于形如"u r"的Q个询问, 回答以 u 节点为中心,半径 r 以内的节点中,权值最大的节点的编号是多少。如果有多个节点,返回编号最小的。

输入

共有一组测试数据。
第一行包含一个整数 n (1 ≤ n ≤ 10^5),表示节点总数。
接下来的一行,包含 n 个数字,表示每个节点的权值 vi (1 ≤ vi ≤ 10^6)。 接下来的 n-1 行,每行三个整数 (ai, bi, wi),表示一条连接 ai, bi 节点的边,边长为 wi(1 ≤ ai, bi ≤ n, 1 ≤ wi ≤ 3)。
接下来的一行包含一个整数 q,表示询问总数(1 ≤ q ≤ 10^5)。 接下来 q 行,每行包含两个整数 u, r(1 ≤ u ≤ n, 0 ≤ r ≤300),表示询问以 u 节点为中心,半径 r 以内的节点中,权值最大的节点的编号是多少。如果有多解返回编号最小的。

输出

对于每组询问,输出一行表示对应答案。

输入示例

7
1 2 3 4 5 6 7
1 2 1
2 3 1
2 4 1
1 5 1
5 6 1
5 7 1
4
1 1
1 2
2 1
2 2

输出示例

5
7
4
5

其他说明

样例很邪恶哦。

考虑用点分治离线来解决这道题,那么问题转换成怎么解决过重心x的询问Max(val[y]|depx+depy<=r)。

我们可以用往常的做法,维护dep、val同时递增的决策序列,这个可以用平衡树来做,然后正反扫一遍。

但其实没有必要,注意x、y在同一棵子树并不会影响答案(想一想,为什么),所以只需离线构出决策序列然后二分就行了。

#include<cstdio>
#include<cctype>
#include<queue>
#include<stack>
#include<cstring>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define ren for(int i=first[x];i;i=next[i])
using namespace std;
inline int read() {
    int x=0,f=1;char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c==‘-‘) f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-‘0‘;
    return x*f;
}
const int maxn=100010;
int first[maxn],next[maxn<<1],to[maxn<<1],dis[maxn<<1],e;
void AddEdge(int w,int v,int u) {
    to[++e]=v;dis[e]=w;next[e]=first[u];first[u]=e;
    to[++e]=u;dis[e]=w;next[e]=first[v];first[v]=e;
}
int n,q,val[maxn],ans[maxn];
int better(int x,int y) {
    if(val[x]<val[y]||(val[x]==val[y]&&x>y)) return 0;
    return 1;
}
void relax(int& x,int y) {if(better(y,x)) x=y;}
struct Query {
    int x,r,id,next;
}Q[maxn];
int first2[maxn],cnt;
void AddQuery(int id,int r,int x) {
    Q[++cnt]=(Query){x,r,id,first2[x]};first2[x]=cnt;
}
int vis[maxn],f[maxn],s[maxn],size,root;
void getroot(int x,int fa) {
    s[x]=1;int maxs=0;
    ren if(to[i]!=fa&&!vis[to[i]]) {
        getroot(to[i],x);
        s[x]+=s[to[i]];maxs=max(maxs,s[to[i]]);
    }
    f[x]=max(maxs,size-s[x]);
    if(f[root]>f[x]) root=x;
}
int tot,num[maxn],dep[maxn],id[maxn],A[maxn],B[maxn];
void dfs(int x,int fa,int D) {
    num[++tot]=x;dep[tot]=D;
    ren if(to[i]!=fa&&!vis[to[i]]) dfs(to[i],x,D+dis[i]);
}
int cmp(int x,int y) {return dep[x]<dep[y]||(dep[x]==dep[y]&&val[num[x]]>val[num[y]]);}
void solve(int x) {
    vis[x]=1;tot=0;dfs(x,0,0);
    rep(i,1,tot) id[i]=i;
    sort(id+1,id+tot+1,cmp);
    int tmp=tot;tot=0;
    rep(i,1,tmp) if(better(num[id[i]],A[tot])) A[++tot]=num[id[i]],B[tot]=dep[id[i]];
    rep(i,1,tmp) for(int j=first2[num[i]];j;j=Q[j].next) {
        int l=1,r=tot+1;
        while(l+1<r) {
            int mid=l+r>>1;
            if(B[mid]<=Q[j].r-dep[i]) l=mid;
            else r=mid;
        }
        if(B[l]<=Q[j].r-dep[i]) relax(ans[Q[j].id],A[l]);
    }
    ren if(!vis[to[i]]) {
        size=f[0]=s[to[i]];getroot(to[i],root=0);
        solve(root);
    }
}
int main() {
    n=read();
    rep(i,1,n) val[i]=read();
    rep(i,2,n) AddEdge(read(),read(),read());
    q=read();
    rep(i,1,q) AddQuery(i,read(),read());
    size=f[0]=n;getroot(1,0);
    solve(root);
    rep(i,1,q) printf("%d\n",ans[i]);
    return 0;
}

时间: 2024-10-07 02:22:13

COJ966 WZJ的数据结构(负三十四)的相关文章

COJ 0970 WZJ的数据结构(负三十)树分治

WZJ的数据结构(负三十) 难度级别:D: 运行时间限制:1000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 给你一棵N个点的无根树,点和边上均有权值.请你设计一个数据结构,回答M次操作. 1 x v:对于树上的每一个节点y,如果将x.y在树上的距离记为d,那么将y节点的权值加上d*v. 2 x:询问节点x的权值. 输入 第一行为一个正整数N.第二行到第N行每行三个正整数ui,vi,wi.表示一条树边从ui到vi,距离为wi.第N+1行为一个正整数M.最后

COJ968 WZJ的数据结构(负三十二)

WZJ的数据结构(负三十二) 难度级别:D: 运行时间限制:5000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 给你一棵N个点的无根树,边上均有权值,每个点上有一盏灯,初始均亮着.请你设计一个数据结构,回答M次操作. 1 x:将节点x上的灯拉一次,即亮变灭,灭变亮. 2 x k:询问当前所有亮灯的节点中距离x第k小的距离(注意如果x亮着也算入). 输入 第一行为一个正整数N.第二行到第N行每行三个正整数ui,vi,wi.表示一条树边从ui到vi,距离为wi

COJ970 WZJ的数据结构(负三十)

WZJ的数据结构(负三十) 难度级别:D: 运行时间限制:1000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 给你一棵N个点的无根树,点和边上均有权值.请你设计一个数据结构,回答M次操作. 1 x v:对于树上的每一个节点y,如果将x.y在树上的距离记为d,那么将y节点的权值加上d*v. 2 x:询问节点x的权值. 输入 第一行为一个正整数N.第二行到第N行每行三个正整数ui,vi,wi.表示一条树边从ui到vi,距离为wi.第N+1行为一个正整数M.最后

44. 蛤蟆的数据结构笔记之四十四弗洛伊德Floyd算法

44. 蛤蟆的数据结构笔记之四十四弗洛伊德Floyd算法 本篇名言:"希望是厄运的忠实的姐妹. --普希金" 我们继续来看下数据结构图中的一个算法,这个算法来自图灵奖得主. 1.  Floyd算法介绍 Floyd算法又称为插点法,是一种用于寻找给定的加权图中多源点之间最短路径的算法.该算法名称以创始人之一.1978年图灵奖获得者.斯坦福大学计算机科学系教授罗伯特·弗洛伊德命名.注意这个可不是心理学的那个弗洛伊德. 是解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权的最短路径

14、蛤蟆的数据结构笔记之十四栈的应用之栈与递归之阿克曼函数

14.蛤蟆的数据结构笔记之十四栈的应用之栈与递归之阿克曼函数 本篇名言:"今天就是生命 ----- 是唯一你能确知的生命." 继续递归应用,阿克曼函数. 欢迎转载,转载请标明出处: 1.  阿克曼函数 阿克曼函数(Ackermann)是非原始递归函数的例子.它需要两个自然数作为输入值,输出一个自然数.它的输出值增长速度非常高,仅是对于(4,3)的输出已大得不能准确计算. Ackermann函数定义如下: 若m=0,返回n+1. 若m>0且n=0,返回Ackermann(m-1,1

Java进阶(三十四)Integer与int的种种比较你知道多少?

Java进阶(三十四)Integer与int的种种比较你知道多少? 前言 如果面试官问Integer与int的区别:估计大多数人只会说到两点:Ingeter是int的包装类,注意是一个类:int的初值为0,Ingeter的初值为null.但是如果面试官再问一下Integer i = 1;int ii = 1; i==ii为true还是为false?估计就有一部分人答不出来了,如果再问一下其他的,估计更多的人会头脑一片混乱.所以我对它们进行了总结,希望对大家有帮助. 首先看代码: package

centos 监控cacti/nagios/zabbix 第三十四节课

centos   监控cacti/nagios/zabbix   第三十四节课 上半节课 下半节课 f

34. 蛤蟆的数据结构笔记之三十四树的概念

34. 蛤蟆的数据结构笔记之三十四树的概念 本篇名言:"过去属于死神,未来属于你自己.--雪莱" 本篇笔记开始我们要进入新的概念了,树!是不是有点小激动呢?让我们从概念开始吧 当然概念要理解,如果当前不能立刻理解,可以后续结合代码一起理解效果更佳. 1.  树型结构 之前我们学习的那么多,其实都是线性数据结构. 树 则不同,它是非线性结构. 树形结构指的是数据元素之间存在着"一对多"的树形关系的数据结构,是一类重要的非线性数据结构.在树形结构中,树根结点没有前驱结点

Python进阶(三十四)-Python3多线程解读

Python进阶(三十四)-Python3多线程解读 线程讲解 ??多线程类似于同时执行多个不同程序,多线程运行有如下优点: 使用线程可以把占据长时间的程序中的任务放到后台去处理. 用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度. 程序的运行速度可能加快. 在一些等待的任务实现上如用户输入.文件读写和网络收发数据等,线程就比较有用了.在这种情况下我们可以释放一些珍贵的资源如内存占用等等. ??线程在执行过程中与进程还是有区别的.每个独立