https://www.cnblogs.com/mountaink/p/9878918.html

分析:每次的选取必须选最优的一条链,那我们考虑一下选择这条链后,把这条路上的点的权值更新掉,再采取选最优的一条链的策略,如此往复。

    所以考虑利用dfs序来处理线段树,线段树维护的是最最优链的值,已经这条链的链跟,的dfs序。

   

#include<bits/stdc++.h>
using namespace std;
#define lson root<<1,l,midd
#define rson root<<1|1,midd+1,r
typedef long long ll;
const int M=2e5+;
struct node{
int v,nextt;
}e[M<<];
ll a[M],tree[M<<],mp[M<<],dis[M<<],lazy[M<<];
int dfn[M],fa[M],cnt,tot,head[M],vis[M],L[M],R[M];
void addedge(int u,int v){
e[cnt].v=v;
e[cnt].nextt=head[u];
head[u]=cnt++;
} void up(int root){
if(tree[root<<]>tree[root<<|]){
tree[root]=tree[root<<];
mp[root]=mp[root<<];
}
else{
tree[root]=tree[root<<|];
mp[root]=mp[root<<|];
} }
void pushdown(int root){
if(lazy[root]){
ll c=lazy[root];
tree[root<<]-=c;
tree[root<<|]-=c;
lazy[root<<]+=c;
lazy[root<<|]+=c;
lazy[root]=;
}
}
void build(int root,int l,int r){
if(l==r){
tree[root]=dis[l],mp[root]=l;
return ;
}
int midd=(l+r)>>;
build(lson);
build(rson);
up(root);
}
void update(int LL,int RR,ll c,int root,int l,int r){
if(LL<=l&&r<=RR){
tree[root]-=c;
lazy[root]+=c;
return ;
}
pushdown(root);
int midd=(l+r)>>;
if(LL<=midd)
update(LL,RR,c,lson);
if(RR>midd)
update(LL,RR,c,rson);
up(root);
}
void dfs(int u,int f){
dfn[++tot]=u;
L[u]=tot;
dis[tot]=a[u]+dis[L[f]];
for(int i=head[u];~i;i=e[i].nextt){
int v=e[i].v;
if(v==f)
continue;
dfs(v,u);
}
R[u]=tot;
}
int main(){
int n,k;
memset(head,-,sizeof(head));
scanf("%d%d",&n,&k);
for(int i=;i<=n;i++)
scanf("%lld",&a[i]);
for(int i=;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
addedge(u,v);
addedge(v,u);
fa[v]=u;
}
int root=;
while(fa[root])
root=fa[root];
//cout<<root<<"~!!"<<endl;
dfs(root,);
build(,,n);
/* for(int i=1;i<=4*n;i++)
cout<<dis[i]<<endl;*/
ll ans=;
int x;
//cout<<"!!"<<endl;
while(k--){
ans+=tree[]; x=mp[];
while(x&&!vis[x]){
update(L[dfn[x]],R[dfn[x]],a[dfn[x]],,,n);
vis[x]=;
x=L[fa[dfn[x]]];
}
}
printf("%lld\n",ans);
return ;
}

http://acm.hdu.edu.cn/showproblem.php?pid=3887

题意:给出一树,求在以每个节点为跟的树中,有几个是比他小的?

分析:用dfs给树进行编号,然后从小到大输出答案(query,是询问俩个dfs序区间)并更新线段树,更新时,是单点更新,+1就行了,因为如果在查询比之前点深度浅的的位置,就肯定会包含比他深度深且是他的子树的dfs序区间

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
#define lson root<<1,l,midd
#define rson root<<1|1,midd+1,r
const int M=5e5+;
int tree[M<<],L[M],R[M],head[M],tot,cnt;
struct node{
int v,nextt;
}e[M];
void addedge(int u,int v){
e[cnt].v=v;
e[cnt].nextt=head[u];
head[u]=cnt++;
}
void up(int root){
tree[root]=tree[root<<]+tree[root<<|];
}
void dfs(int u,int f){
L[u]=++tot;
for(int i=head[u];~i;i=e[i].nextt){
int v=e[i].v;
if(v==f)
continue;
dfs(v,u);
}
R[u]=tot;
}
void build(int root,int l,int r){
if(l==r){
tree[root]=;
return;
}
int midd=(l+r)>>;
build(lson);
build(rson);
}
void update(int pos,int c,int root,int l,int r){
if(l==r){
tree[root]+=c;
return ;
}
int midd=(l+r)>>;
if(pos<=midd)
update(pos,c,lson);
else
update(pos,c,rson);
up(root);
}
int query(int L,int R,int root,int l,int r){
if(L<=l&&r<=R){
return tree[root];
}
int midd=(l+r)>>;
int ans=;
if(L<=midd)
ans+=query(L,R,lson);
if(R>midd)
ans+=query(L,R,rson);
return ans;
}
int main(){
int n,root;
while(~scanf("%d%d",&n,&root)){
if(n==&&root==)
break;
tot=,cnt=;
for(int i=;i<=n;i++)
head[i]=-;
memset(tree,,sizeof(tree));
for(int i=;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
addedge(u,v);
addedge(v,u);
}
dfs(root,-);
build(,,n);
for(int i=;i<=n;i++){
printf("%d",query(L[i],R[i],,,n));
if(i==n)
printf("\n");
else
printf(" ");
update(L[i],,,,n);
} }
return ;
}

http://poj.org/problem?id=3321

题意:给出一颗苹果树,起初每个节点点权为1,然后询问是以询问节点为根问有多少个苹果,更新是单点更新,1->0,0->1

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define lson root<<1,l,midd
#define rson root<<1|1,midd+1,r
using namespace std;
typedef long long ll;
const int M=1e5+;
struct node{
int v,nextt;
}e[M<<];
int tree[M<<],vis[M],L[M],R[M],cnt,tot,head[M];
void addedge(int u,int v){
e[cnt].v=v;
e[cnt].nextt=head[u];
head[u]=cnt++;
}
void up(int root){
tree[root]=tree[root<<]+tree[root<<|];
}
void build(int root,int l,int r){
if(l==r){
tree[root]=;
return;
}
int midd=(l+r)>>;
build(lson);
build(rson);
up(root);
}
int query(int L,int R,int root,int l,int r){ if(L<=l&&r<=R){
return tree[root]; }
int midd=(l+r)>>;
int ans=;
if(L<=midd)
ans+=query(L,R,lson);
if(R>midd)
ans+=query(L,R,rson);
return ans;
}
void update(int pos,int c,int root,int l,int r){
if(l==r){
tree[root]+=c;
return ;
}
int midd=(l+r)>>;
if(pos<=midd)
update(pos,c,lson);
else
update(pos,c,rson);
up(root);
}
void dfs(int u,int f){
L[u]=++tot;
for(int i=head[u];~i;i=e[i].nextt){
int v=e[i].v;
if(v==f)
continue;
dfs(v,u);
}
R[u]=tot;
}
char s[];
int main(){
int n;
scanf("%d",&n);
memset(head,-,sizeof(head));
for(int i=;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
addedge(u,v);
addedge(v,u);
}
dfs(,);
build(,,n);
int m;
scanf("%d",&m);
while(m--){ int x;
scanf("%s%d",s,&x);
if(s[]=='Q'){
printf("%d\n",query(L[x],R[x],,,n));
}
else{
if(vis[x]==)
update(L[x],-,,,n),vis[x]=;
else
update(L[x],,,,n),vis[x]=;
} }
return ;
}

http://codeforces.com/problemset/problem/620/E

分析:和数颜色的那道线段树题目差不多,只不过把树转化成dfs序而已。注意,在build时,要用dfn数组,而非L数组!!!!

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<vector>
#define lson root<<1,l,midd
#define rson root<<1|1,midd+1,r
using namespace std;
typedef long long ll;
const int M=4e5+;
struct node{
int v,nextt;
}e[M<<];
ll tree[M<<],lazy[M<<];
int L[M],R[M],head[M],tot,cnt,a[M],dfn[M];
void up(int root){
tree[root]=(tree[root<<]|tree[root<<|]);
}
void pushdown(int root){
if(lazy[root]){
ll c=lazy[root];
lazy[root<<]=c,lazy[root<<|]=c;
tree[root<<]=c,tree[root<<|]=c;
lazy[root]=0ll;
}
}
void build(int root,int l,int r){
if(l==r){
tree[root]=(1ll<<(a[dfn[l]]-))*1ll;
return ;
}
int midd=(l+r)>>;
build(lson);
build(rson);
up(root);
}
void update(int L,int R,int c,int root,int l,int r){
if(L<=l&&r<=R){
tree[root]=(1ll<<(c-))*1ll;
lazy[root]=(1ll<<(c-))*1ll;
return ;
}
pushdown(root);
int midd=(l+r)>>;
if(L<=midd)
update(L,R,c,lson);
if(R>midd)
update(L,R,c,rson);
up(root);
}
ll query(int LL,int RR,int root,int l,int r){
if(LL<=l&&r<=RR){
return tree[root];
}
ll ans=;
pushdown(root);
int midd=(l+r)>>;
if(LL<=midd)
ans|=query(LL,RR,lson);
if(RR>midd)
ans|=query(LL,RR,rson);
up(root);
return ans;
}
void dfs(int u,int f){
L[u]=++tot;
dfn[tot]=u;
for(int i=head[u];~i;i=e[i].nextt){
int v=e[i].v;
if(v==f)
continue;
dfs(v,u);
}
R[u]=tot;
}
void addedge(int u,int v){
e[cnt].v=v;
e[cnt].nextt=head[u];
head[u]=cnt++;
}
int sum(ll x){
int t=;
while(x){
if(x&)
t++;
x>>=; }
return t;
}
int main(){
int n,m;
memset(head,-,sizeof(head));
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++){
scanf("%d",&a[i]);
}
for(int i=;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
addedge(u,v);
addedge(v,u);
}
dfs(,);
build(,,n);
while(m--){
int op;
scanf("%d",&op);
if(op==){
int x,y;
scanf("%d%d",&x,&y);
update(L[x],R[x],y,,,n);
}
else{
int x;
scanf("%d",&x);
printf("%d\n",sum(query(L[x],R[x],,,n)));
}
}
return ;
}

用dfs序处理线段树的好题吗?的更多相关文章

  1. bzoj3306: 树(dfs序+倍增+线段树)

    比较傻逼的一道题... 显然求子树最小值就是求出dfs序用线段树维护嘛 换根的时候树的形态不会改变,所以我们可以根据相对于根的位置分类讨论. 如果询问的x是根就直接输出整棵树的最小值. 如果询问的x是 ...

  2. bzoj2819 DFS序 + LCA + 线段树

    https://www.lydsy.com/JudgeOnline/problem.php?id=2819 题意:树上单点修改及区间异或和查询. 思维难度不高,但是题比较硬核. 整体思路是维护每一个结 ...

  3. Codeforces 877E - Danil and a Part-time Job(dfs序+线段树)

    877E - Danil and a Part-time Job 思路:dfs序+线段树 dfs序:http://blog.csdn.net/qq_24489717/article/details/5 ...

  4. 7月13日考试 题解(DFS序+期望+线段树优化建图)

    T1 sign 题目大意:给出一棵 N 个节点的树,求所有起点为叶节点的有向路径,其 上每一条边权值和的和.N<=10000 水题.考试的时候毒瘤出题人(学长orz)把读入顺序改了一下,于是很多 ...

  5. hdu 3974 Assign the task(dfs序上线段树)

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

  6. Luogu P2982 [USACO10FEB]慢下来 Slowing down | dfs序、线段树

    题目链接 题目大意: 有一棵N个结点树和N头奶牛,一开始所有奶牛都在一号结点,奶牛们将按从编号1到编号N的顺序依次前往自己的目的地,求每头奶牛在去往自己目的地的途中将会经过多少已经有奶牛的结点. 题解 ...

  7. Codeforces Round #200 (Div. 1) D. Water Tree(dfs序加线段树)

    思路: dfs序其实是很水的东西.  和树链剖分一样, 都是对树链的hash. 该题做法是:每次对子树全部赋值为1,对一个点赋值为0,查询子树最小值. 该题需要注意的是:当我们对一棵子树全都赋值为1的 ...

  8. hdu4366 Successor (dfs序+zkw线段树)

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

  9. URAL 1890 . Money out of Thin Air (dfs序hash + 线段树)

    题目链接: URAL 1890 . Money out of Thin Air 题目描述: 给出一个公司里面上司和下级的附属关系,还有每一个人的工资,然后有两种询问: 1:employee x y z ...

随机推荐

  1. maven中的groupId和artifactId 区分

    原文地址:https://blog.csdn.net/snowin1994/article/details/53024871/ maven中的groupId和artifactId 区分 groupid ...

  2. aliyun二级域名绑定

    NameVirtualHost *:80 开启监听 <VirtualHost *:80>    DocumentRoot /home/service/    ServerName serv ...

  3. HDU 1298 T9 字典树+DFS

    必须要批评下自己了,首先就是这个题目的迟疑不定,去年做字典树的时候就碰到这个题目了,当时没什么好的想法,就暂时搁置了,其实想法应该有很多,只是居然没想到. 同样都是对单词进行建树,并插入可能值,但是拨 ...

  4. (1)opencv的安装和遇到的问题

    opencv的安装主要是看的这个博客 https://blog.csdn.net/w_chaoqi/article/details/81949738 然后在把代码粘贴上时,出现,不识别我的opencv ...

  5. 1)warning LNK4233

    名称 test.exe 包含非 ASCII 字符,在具有除 936 以外的 ANSI 代码页的系统上可能不能加载 DLL 名称 练习动态库.dll 包含非 ASCII 字符,如果系统没有与用于链接此 ...

  6. B - Given Length and Sum of Digits... CodeForces - 489C (贪心)

    You have a positive integer m and a non-negative integer s. Your task is to find the smallest and th ...

  7. Django模板渲染——(二)

    模板标签 模板是由HTML代码和一些逻辑控制代码组成的,逻辑控制代码除了前面介绍的变量和过滤器,还要一个非常重要的模板标签.模板标签的语法规则是{% tag %},模板标签在渲染的过程中能提供任意的逻 ...

  8. memset的常见用法

    头文件 <cstring> 描述 因为memset函数按照字节填充,所以一般memset只能用来填充char型数组 ------------------------------------ ...

  9. 在阿里做了5年技术Leader,我总结出这些套路!

    转自 51CTO技术栈 内容 团队建设 团队管理 团队文化 沟通与辅导 招聘与解雇 互联网公司的技术团队管理通常分为两个方向:技术管理和团队管理,互联网公司的技术 TL 与传统软件公司的 PM 还是有 ...

  10. Go语言集成开发环境之GoLand安装使用

    下载Go语言开发包 大家可以在Go语言官网(https://golang.google.cn/dl/)下载 Windows 系统下的Go语言开发包,如下图所示. 这里我们下载的是 64 位的开发包,如 ...