给定一颗树,每个节点都有忠诚和能力两个参数,随意指定一个节点,要求在它的子树中找一个节点代替它,这个节点要满足能力值大于它,而且是忠诚度最高的那个。

首先,dfs一下,处理出L[i], R[i]表示dfs序,则R[i] - L[i] + 1 就是当前i这个节点拥有的子孙个数。

对于一颗树,dfs的时候,访问节点有先后顺序,那么可以用一个struct node List[maxn];表示这课树中访问的先后顺序。

例如这颗树,我假设是先访问0 --> 3 --> 2 ---> 4 ---> 5 ---> 1

这样我用一个List数组保存了,同时记录了L[i]和R[i]。那么对于每次询问删除一个节点cur,就是在[L[cur], R[cur]]里面选择了。例如节点2,L[2] = 2, R[2] = 4。那么就变成了区间最值问题。

分块:块内维护一个数组mx[i]表示当前这个块内能力值 > List[i].ablity的最大忠诚度。想要维护这个,就要开多个数组to_sort[]同样是记录dfs序,但是它要排序,按能力排序,这样可以O(magic)维护完成。

对于每个查询,不在块内的,暴力,在的,二分出一个 > 当前能力的pos,mx[pos]就是答案。

复杂度 O (nsqrt(n) + msqrt(n) * logn)

感觉数据略水,应该用线段树优化掉sqrt(n)

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL; #include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
const int maxn = + ;
struct edge {
int u, v, next;
} e[maxn * ];
int first[maxn], R[maxn], L[maxn], mx[maxn];
int magic;
struct node {
int abliatly, loyalty ;
bool operator < (const node &rhs) const {
return abliatly < rhs.abliatly;
}
} a[maxn], List[maxn], to_sort[maxn];
int get_id[ + ];
int n, num;
void add (int u, int v)
{
++num;
e[num].u = u;
e[num].v = v;
e[num].next = first[u];
first[u] = num;
}
bool book[maxn];
int index;
void dfs (int cur)
{
L[cur] = index;
for (int i = first[cur]; i; i = e[i].next) {
if (book[e[i].v]) continue;
book[e[i].v] = ;
++index;
List[index] = to_sort[index] = a[e[i].v];
dfs (e[i].v);
}
R[cur] = index;
}
int find (int begin, int end, int val)
{
int t = end;
if (to_sort[end].abliatly < val) return -; //不够它大
if (to_sort[begin].abliatly > val) return mx[begin];//bigger
while (begin <= end) {
int mid = (begin + end) >> ;
if (to_sort[mid].abliatly > val) end = mid - ;
else begin = mid + ;
}
if (begin > t) return -;
return mx[begin];
}
void work ()
{
int Q;
scanf ("%d%d", &n, &Q);
magic = (int) sqrt (n * 1.0);
for (int i = ; i <= n - ; ++i) {
int fa, lo, ab;
scanf ("%d%d%d", &fa, &lo, &ab);
add (fa, i);
a[i].abliatly = ab;
a[i].loyalty = lo;
get_id[lo] = i;
}
dfs (); //dfs 构图
for (int i = ; i < n; i += magic) {
int j = i + magic;
if (j > n) break;
sort (to_sort + i, to_sort + j);
mx[j - ] = to_sort[j - ].loyalty;
for (int k = j - ; k >= i; --k) {
mx[k] = mx[k + ] > to_sort[k].loyalty ? mx[k + ] : to_sort[k].loyalty;
}
}
while (Q--) {
int id;
scanf ("%d", &id);
int val = a[id].abliatly;
int ans = -inf;
int begin = L[id], end = R[id];
for (int i = begin; i <= end;) {
if (i % magic == && i + magic - <= end) {
int t = find (i, i + magic - , val);
ans = max (ans, t);
i += magic;
} else {
if (List[i].abliatly > val && ans < List[i].loyalty) {
ans = List[i].loyalty;
}
++i;
}
}
printf ("%d\n", ans < ? - : get_id[ans]);
}
return ;
} int main ()
{
#ifdef local
freopen("data.txt","r",stdin);
#endif
int t;
scanf ("%d", &t);
a[].abliatly = -;
a[].loyalty = -;
List[] = to_sort[] = a[];
while (t--) {
work ();
memset (first, , sizeof first);
memset (book, , sizeof book);
num = ;
index = ;
memset (mx, , sizeof mx);
}
return ;
}

线段树预处理优化:

同样是dfs序处理好,然后按能力从大到小排序,相同的,按id从小到大排序。因为id小的,必然不能成为后面的替身。

然后首先把线段树初始化为-1,按照能力从大到小去线段树L[id] --- R[id]中查找。

id就是那个cur,因为它的边是fa -- i的。//正因为这样,才能用这种方法

为什么呢? 如果它建树的过程不是这样的话,就是不是一直往下建,(这样确保了id小的一定更高级)。这样就没法用id去比较它们的关系了。这个时候,只能分块做了。

然后就从大到小加入线段树,确保每次查找都是有效值即可

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL; #include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
const int maxn = + ;
struct edge {
int u, v;
int next;
} e[maxn * ];
struct node {
int loyalty, ability, id;
bool operator < (const node &rhs) const {
if (ability != rhs.ability) return ability > rhs.ability;
else return id < rhs.id;
}
} a[maxn];
int num;
int first[maxn], L[maxn], R[maxn], get_id[ + ];
void add (int u, int v)
{
++num;
e[num].u = u;
e[num].v = v;
e[num].next = first[u];
first[u] = num;
}
bool book[maxn];
int index;
void dfs (int cur)
{
L[cur] = index;
for (int i = first[cur]; i; i = e[i].next) {
if (book[e[i].v] == ) {
book[e[i].v] = ;
index++;
dfs (e[i].v);
}
}
R[cur] = index;
}
struct data {
int L,R,mx; //每个节点,都记录一个区间[L,R]。还有记录区间总和
int mid() {
return (L + R)/;
}
} SegTree[maxn<<]; //右移两位,就是*4 void built (int root,int begin,int end)
{
SegTree[root].L = begin;
SegTree[root].R = end;//覆盖区间
if (begin == end) {
SegTree[root].mx = -;
return ;
}
built(root<<,begin,SegTree[root].mid());
built(root<<|,SegTree[root].mid()+,end);
SegTree[root].mx = max(SegTree[root<<].mx,SegTree[root<<|].mx);
return ;
}
void addTT (int root,int pos,int val)
{
if (SegTree[root].L == pos && pos == SegTree[root].R) {
SegTree[root].mx = val;
return ;
}
if (pos <= SegTree[root].mid()) addTT(root<<,pos,val);
else if (pos >= SegTree[root].mid()+) addTT(root<<|,pos,val);
SegTree[root].mx = max (SegTree[root<<].mx,SegTree[root<<|].mx);
return ;
}
//[begin,end]是要查询的区间,如果所求区间包含线段树覆盖区间,就可以返回
int find (int root,int begin,int end) //区间查询
{
//查询[1,7]的话,左子树区间覆盖了[1,6],也可以直接返回,左子树最大值嘛
if (begin <= SegTree[root].L && end >= SegTree[root].R)
return SegTree[root].mx; //覆盖了
if (end <= SegTree[root].mid()) //完全在左子数
return find(root<<,begin,end);
else if (begin >= SegTree[root].mid() + ) //完全在右子树
return find(root<<|,begin,end);
else {
int Lmax = find(root<<,begin,end);
int Rmax = find(root<<|,begin,end);
return max(Lmax,Rmax);
}
}
int ans[maxn];
void work ()
{
int n, Q;
scanf ("%d%d", &n, &Q);
for (int i = ; i <= n - ; ++i) {
int fa, lo, ab;
scanf ("%d%d%d", &fa, &lo, &ab);
add (fa, i);
a[i].loyalty = lo;
a[i].ability = ab;
a[i].id = i;
get_id[lo] = i;
}
dfs ();
// for (int i = 0; i < n; ++i) {
// printf ("%d %d\n", L[i], R[i]);
// }
built (, , n - ); //全部设置为-1先
sort (a + , a + n);
// for (int i = 1; i <= n - 1; ++i) {
// printf ("%d %d\n", a[i].ability, a[i].loyalty);
// }
for (int i = ; i <= n - ; ++i) {
int id = get_id[a[i].loyalty];
//printf ("%d****\n", id);
// printf ("%d %d\n", L[id], R[id]);
int t = find (, L[id], R[id]);
//ans[id] = t;
if (t == -) {
ans[id] = -;
} else {
ans[id] = get_id[t];
}
addTT (, L[id], a[i].loyalty);
}
for (int i = ; i <= Q; ++i) {
int id;
scanf ("%d", &id);
printf ("%d\n", ans[id]);
}
return ;
} int main ()
{
#ifdef local
freopen("data.txt","r",stdin);
#endif
int t;
scanf ("%d", &t);
while (t--) {
index = ;
work ();
memset (book, , sizeof book);
memset (first, , sizeof first);
index = ;
num = ;
}
return ;
}

HDU - 4366 Successor DFS序 + 分块暴力 or 线段树维护的更多相关文章

  1. HDU 4366 Successor( DFS序+ 线段树 )

    Successor Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total S ...

  2. HDU - 4366 Successor DFS区间+线段树

    Successor:http://acm.hdu.edu.cn/showproblem.php?pid=4366 参考:https://blog.csdn.net/colin_27/article/d ...

  3. hdu 4366 Successor - CDQ分治 - 线段树 - 树分块

    Sean owns a company and he is the BOSS.The other Staff has one Superior.every staff has a loyalty an ...

  4. HDU 4366 Successor(树链剖分+zkw线段树+扫描线)

    [题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=4366 [题目大意] 有一个公司,每个员工都有一个上司,所有的人呈树状关系,现在给出每个人的忠诚值和 ...

  5. HDU.5692 Snacks ( DFS序 线段树维护最大值 )

    HDU.5692 Snacks ( DFS序 线段树维护最大值 ) 题意分析 给出一颗树,节点标号为0-n,每个节点有一定权值,并且规定0号为根节点.有两种操作:操作一为询问,给出一个节点x,求从0号 ...

  6. Assign the task HDU - 3974(dfs序+线段树)

    There is a company that has N employees(numbered from 1 to N),every employee in the company has a im ...

  7. 【bzoj4009】[HNOI2015]接水果 DFS序+树上倍增+整体二分+树状数组

    题目描述 给出一棵n个点的树,给定m条路径,每条路径有一个权值.q次询问求一个路径包含的所有给定路径中权值第k小的. 输入 第一行三个数 n和P 和Q,表示树的大小和盘子的个数和水果的个数. 接下来n ...

  8. P3703 [SDOI2017]树点涂色 LCT维护颜色+线段树维护dfs序+倍增LCA

    \(\color{#0066ff}{ 题目描述 }\) Bob有一棵\(n\)个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同. 定义一条路径的权值是:这条路径上的点 ...

  9. CF877E Danil and a Part-time Job 线段树维护dfs序

    \(\color{#0066ff}{题目描述}\) 有一棵 n 个点的树,根结点为 1 号点,每个点的权值都是 1 或 0 共有 m 次操作,操作分为两种 get 询问一个点 x 的子树里有多少个 1 ...

随机推荐

  1. CF 1036B Diagonal Walking v.2——思路

    题目:http://codeforces.com/contest/1036/problem/B 比赛时只能想出不合法的情况还有走到终点附近的方式. 设n<m,不合法就是m<k.走到终点方式 ...

  2. win7下vs2010开发atl服务

    问题一: 编译服务后,提示出下错误 Microsoft.CppCommon.targets(113,5): error MSB3073: 命令 " ***.exe "  /RegS ...

  3. 如何在windows 2003(虚拟主机)上面部署MVC3

    相信有很多朋友和我一样遇到了这个问题,网上大牛说的都不是很清楚,关于这个问题我详细的跟进一下 这个问题呢大致分为两种情况 一.有服务器的控制权限,这个就简单很多, 1.安装mvc3支持组件2.如果可以 ...

  4. 使用svnadmin对VisualSVN进行项目迁移

    使用svnadmin对VisualSVN进行项目迁移 导出1> 启动命令行cmd2> 运行%VISUALSVN_SERVER%\bin\svnadmin dump PATH-TO-REPO ...

  5. JVM体系结构之三:方法区之1

    一.简介 方法区在JVM中也是一个非常重要的区域,它与堆一样,是被线程共享的区域.在方法区中,存储了每个类的信息(包括类的名称.方法信息.字段信息).静态变量.常量以及编译器编译后的代码等. 方法区( ...

  6. python 基础 列表生成式

    data = {'a':'abc';'b':'bac','c':'cba'} [v for k,v in data] 结果 ['abc','bca','cba'] 格式 [x for x in  内容 ...

  7. static和final的区别

    1.static是静态修饰关键字,可以修饰变量和程序块以及类方法: 当你定义一个static的变量的时候jvm会将将其分配在内存堆上,所有程序对它的引用都会指向这一个地址而不会重新分配内存: 修饰一个 ...

  8. Windows 10 PC 安装 Docker CE

    系统要求 Docker CE 支持 64 位版本的 Windows 10 Pro,且必须开启 Hyper-V. 如果系统是win 10 家庭版安装 docker  很恶心, 我也是废了2天才安装, 由 ...

  9. iOS开发中,修改ASIHTTPRequest源码,禁止在POST时URL编码

    通过ASIHTTPRequest库进行POST时,会对POST的文本内容进行encodeURL,而且ASIHTTPRequest自身并没有配置项可以关闭这个转换. 本文提供一个方法关闭encodeUR ...

  10. 阶段4-独挡一面\项目-基于视频压缩的实时监控系统\Sprint1-基于Epoll架构的采集端程序框架设计\第2课-基于Epoll的采集端程序框架设计

    回顾之前的整个程序架构 把epoll机制应用到这个架构上去 下面主要去分析我们的系统中有没有需要等待的事件,先看看采集子系统 在采集子系统当中,摄像头有数据,摄像头采集到图像数据可以作为一个等待事件. ...