洛谷 P3258 [JLOI2014]松鼠的新家(树链剖分)
题目描述
松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的。天哪,他居然真的住在”树“上。
松鼠想邀请小熊维尼前来参观,并且还指定一份参观指南,他希望维尼能够按照他的指南顺序,先去a1,再去a2,......,最后到an,去参观新家。可是这样会导致维尼重复走很多房间,懒惰的维尼不停地推辞。可是松鼠告诉他,每走到一个房间,他就可以从房间拿一块糖果吃。
维尼是个馋家伙,立马就答应了。现在松鼠希望知道为了保证维尼有糖果吃,他需要在每一个房间各放至少多少个糖果。
因为松鼠参观指南上的最后一个房间an是餐厅,餐厅里他准备了丰盛的大餐,所以当维尼在参观的最后到达餐厅时就不需要再拿糖果吃了。
输入输出格式
输入格式:
第一行一个整数n,表示房间个数第二行n个整数,依次描述a1-an接下来n-1行,每行两个整数x,y,表示标号x和y的两个房间之间有树枝相连。
输出格式:
一共n行,第i行输出标号为i的房间至少需要放多少个糖果,才能让维尼有糖果吃。
输入输出样例
输入样例#1:
5
1 4 5 3 2
1 2
2 4
2 3
4 5
输出样例#1:
1
2
1
2
1
说明
2<= n <=300000
题解:看来一般难度比树链剖分模板简单的题一般都不难……
很简单的一道树链剖分,每次就是路径修改,注意一个坑点,不要把一趟的终点加完再在下一趟又把它当起点加上去,这样会有重复……
可以预处理出i-i+1的路径上第一个点的位置,但是这不够粗暴,只需要每次加完顺便把这个点减一减就行了,我是最暴力的在线段树上减,其实可以完全点查询答案的时候再减
事实证明区别不大,都会t成狗
但复杂度是对的,所以这道题最恶心在卡常上
我不会卡常,于是我开了o2,就这么a掉了……
代码如下:
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define lson root<<1
#define rson root<<1|1
#define hi puts("hi");
using namespace std; struct node
{
int lazy,sum,l,r;
} tr[];
int a[],fa[],son[],size[],deep[],top[],id[],cnt,ans[];
vector<int> g[]; void push_up(int root)
{
tr[root].sum=tr[lson].sum+tr[rson].sum;
} void push_down(int root)
{
int mid=(tr[root].l+tr[root].r)>>;
tr[lson].sum+=tr[root].lazy*(mid-tr[root].l+);
tr[lson].lazy+=tr[root].lazy;
tr[rson].sum+=tr[root].lazy*(tr[root].r-mid);
tr[rson].lazy+=tr[root].lazy;
tr[root].lazy=;
} void build(int root,int l,int r)
{
if(l==r)
{
tr[root].l=l;
tr[root].r=r;
tr[root].sum=;
return ;
}
tr[root].l=l;
tr[root].r=r;
int mid=(l+r)>>;
build(lson,l,mid);
build(rson,mid+,r);
push_up(root);
} void update(int root,int l,int r,int val)
{
if(tr[root].l==l&&tr[root].r==r)
{
tr[root].sum+=val*(tr[root].r-tr[root].l+);
tr[root].lazy+=val;
return ;
}
if(tr[root].lazy)
{
push_down(root);
}
int mid=(tr[root].l+tr[root].r)>>;
if(l>mid)
{
update(rson,l,r,val);
}
else
{
if(r<=mid)
{
update(lson,l,r,val);
}
else
{
update(lson,l,mid,val);
update(rson,mid+,r,val);
}
}
push_up(root);
} int query(int root,int l,int r)
{
if(l==tr[root].l&&r==tr[root].r)
{
return tr[root].sum;
}
if(tr[root].lazy)
{
push_down(root);
}
int mid=(tr[root].l+tr[root].r)>>;
if(l>mid)
{
return query(rson,l,r);
}
else
{
if(mid>=r)
{
return query(lson,l,r);
}
else
{
return query(lson,l,mid)+query(rson,mid+,r);
}
}
} void dfs1(int now,int f,int dep)
{
fa[now]=f;
deep[now]=dep;
size[now]=;
int maxson=-;
for(int i=; i<g[now].size(); i++)
{
if(g[now][i]==f)
{
continue;
}
dfs1(g[now][i],now,dep+);
size[now]+=size[g[now][i]];
if(size[g[now][i]]>maxson)
{
maxson=size[g[now][i]];
son[now]=g[now][i];
}
}
} void dfs2(int now,int topf)
{
id[now]=++cnt;
top[now]=topf;
if(!son[now])
{
return ;
}
dfs2(son[now],topf);
for(int i=; i<g[now].size(); i++)
{
if(g[now][i]==fa[now]||g[now][i]==son[now])
{
continue;
}
dfs2(g[now][i],g[now][i]);
}
} void path_update(int x,int y)
{
while(top[x]!=top[y])
{
if(deep[top[x]]<deep[top[y]])
{
swap(x,y);
}
update(,id[top[x]],id[x],);
x=fa[top[x]];
}
if(deep[x]>deep[y])
{
swap(x,y);
}
update(,id[x],id[y],);
} void dfs3(int now,int f)
{
ans[now]=query(,id[now],id[now]);
for(int i=; i<g[now].size(); i++)
{
if(g[now][i]==fa[now])
{
continue;
}
dfs3(g[now][i],now);
}
} int main()
{
int n;
scanf("%d",&n);
for(int i=; i<=n; i++)
{
scanf("%d",&a[i]);
}
for(int i=; i<=n-; i++)
{
int from,to;
scanf("%d%d",&from,&to);
g[from].push_back(to);
g[to].push_back(from);
}
dfs1(,,);
dfs2(,);
build(,,n);
for(int i=; i<=n-; i++)
{
path_update(a[i],a[i+]);
update(,id[a[i]],id[a[i]],-);
}
dfs3(,);
ans[a[]]++;
ans[a[n]]--;
for(int i=; i<=n; i++)
{
printf("%d\n",ans[i]);
}
}
洛谷 P3258 [JLOI2014]松鼠的新家(树链剖分)的更多相关文章
- 洛谷 P3258 [JLOI2014]松鼠的新家 树链剖分+差分前缀和优化
目录 题面 题目链接 题目描述 输入输出格式 输入格式 输出格式 输入输出样例 输入样例: 输出样例: 说明 说明 思路 AC代码 优化 优化后AC代码 总结 题面 题目链接 P3258 [JLOI2 ...
- P3258 [JLOI2014]松鼠的新家 树链剖分
这个题就是一道树剖板子题,就是每走一步就把所有的经过点加一就行了.还有,我的树剖板子没问题!!!谁知道为什么板子T3个点!我不管了!反正这道题正常写A了. 题干: 题目描述 松鼠的新家是一棵树,前几天 ...
- 洛谷 P3258 [JLOI2014]松鼠的新家 解题报告
P3258 [JLOI2014]松鼠的新家 题目描述 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他 ...
- 洛谷P3258 [JLOI2014]松鼠的新家
P3258 [JLOI2014]松鼠的新家 题目描述 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他 ...
- 洛谷 P3258 [JLOI2014]松鼠的新家 题解
P3258 [JLOI2014]松鼠的新家 题目描述 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他 ...
- BZOJ 3631: [JLOI2014]松鼠的新家( 树链剖分 )
裸树链剖分... ------------------------------------------------------------------- #include<bits/stdc++ ...
- Bzoj 3631: [JLOI2014]松鼠的新家(树链剖分+线段树)
3631: [JLOI2014]松鼠的新家 Time Limit: 10 Sec Memory Limit: 128 MB Description 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个 ...
- 洛谷P3258 [JLOI2014]松鼠的新家(树上差分+树剖)
题目描述 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他居然真的住在”树“上. 松鼠想邀请小熊维尼前 ...
- 洛谷——P3258 [JLOI2014]松鼠的新家
https://www.luogu.org/problem/show?pid=3258 题目描述 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到 ...
随机推荐
- oracle管理权限和角色
介绍 这一部分主要看看oracle中如何管理权限和角色,权限和角色的区别在哪里. 当刚刚建立用户时,用户没有任何权限,也不能执行任何操作.如果要执行某种特定的数据库操作,则必需为其授予系统的权限:如果 ...
- java基础笔记(6)----面向对象的三大特性
简介:面向对象的三大特性就是封装,继承,多态,是面向对象的核心. 封装 简介:封装是类的边界,可以对数据起到保护作用 特性:属性私有,提供公开的get/set方法 属性私有:private 数据类型 ...
- Go语言标准库_输入/输出
Go语言标准库_输入/输出 转载节选自<Go语言标准库> Reader 接口 type Reader interface { Read(p []byte) (n int, err erro ...
- C语言程序设计(基础)- 第7周作业(新)
要求一(25经验值) 完成PTA中题目集名为<usth-C语言基础-第七周作业>和<usth-C语言基础-12周PTA作业>中的所有题目. 注意1:<usth-C语言基础 ...
- Python实现栈
栈的操作 Stack() 创建一个新的空栈 push(item) 添加一个新的元素item到栈顶 pop() 弹出栈顶元素 peek() 返回栈顶元素 is_empty() 判断栈是否为空 size( ...
- 完美解决ubuntu Desktop 16.04 中文版firefox在非root用户不能正常启动的问题
ubuntu安装好后,默认安装有firefox浏览器,不过,非root的账户登录,双击firefox图标,居然出现如下提示:Your Firefox profile cannot be loaded. ...
- php面向对象相关内容
1.什么是面向对象? 面向对象编程(Object Oriented Programming, OOP, 面向对象程序设计)是一种计算机编程架构,OOP的一条基本原则是计算机程序是由单个能够起到子程序作 ...
- php的数组的函数
1.可以将一个二位数组转化成两个一维数组,没有指定键就是默认的索引 注意二位数组有几种类型,其中最常见的一种是外层循环是一个索引数组,然后内层是一个关联数组.这种通过便利第一层,然后第二层指定关联词就 ...
- ORA-00379 缓冲池 DEFAULT 中无法提供 32K 块大小的空闲缓冲区
(一)问题 今天在使用Pl/sql developer查看表空间大小的时候,报错误:ORA-00379 缓冲池 DEFAULT 中无法提供 32K 块大小的空闲缓冲区,具体如下图: SQL> s ...
- java对象转字节数组,获取泛型类
对象转字节数组,字节数组在恢复成对象 Test.java class Test { public static void main(String args[]) throws IOException, ...