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. 从结构和数字看OO——面向对象设计与构造第一章总结

    不知不觉中,我已经接触OO五周了,顺利地完成了第一章节的学习,回顾三次编程作业,惊喜于自身在设计思路和编程习惯已有了一定的改变,下面我将从度量分析.自身Bug.互测和设计模式四个方向对自己第一章的学习 ...

  2. 第32&35章 数据库的安装&存储实力的管理

    第32章 数据库的安装IO取决于磁盘的个数和接口带宽 版本安装顺序是从低到高存储架构师 第35章 存储实例的管理ASM配置说白了就是ORACLE自己的,不通过操作系统对磁盘进行管理.fdisk -l查 ...

  3. mybatis-地区三表生成地区树

    package com.dhht.manager.vo.area; import lombok.Data; import java.io.Serializable;import java.util.L ...

  4. Java学习十五

    学习内容: MyBaits 以前从来没有接触过mybatis,通过今天的学习知道这是一个框架,适用于关注SQL优化和需要频繁更新的项目. 今天做一个关于mybatis项目的入门小程序,效果很不理想. ...

  5. JAVA 算法练习(二)

    和上次一样,虽说用 java 语言,但有 c 的基础一样可以看懂哦. 机器人走方格问题Ⅰ 题目概述 有一个XxY的网格,一个机器人只能走格点且只能向右或向下走,要从左上角走到右下角.请设计一个算法,计 ...

  6. Ctrl +c 脚本中

    #!/bin/bashsar -n DEV 1 111111111111111 >>1.txt &   #实时网卡流量数据  sleep 3 && kill -2 ...

  7. 利用salt-stack 对多台分布式应用进行简单部署jar包项目:

    /appsystems/JQM-SERVER/shell/stopServer.sh:                                         ----用脚本停止应用 cmd. ...

  8. windows 安装Bitcoin Core使用

    1.官网下载https://bitcoin.org/en/download 选择Windows  其他系统就选择对应的就好 2.双击安装完过后,进入bin目录,打开bitcoin-qt.exe运行,提 ...

  9. 题解【语文1(chin1)- 理理思维】

    link 喵~珂朵莉树AC 珂朵莉树?见此处~ 这数据结构太暴力了,所以不讲了 Code: #include<iostream> #include<cstdio> #inclu ...

  10. Faraday Future,FF2019年一季度前完成第一阶段5亿美元左右的A+轮融资,2019年年底前完成7亿美元的Pre-IPO轮融资,2020IPO

    FF2019年一季度前完成第一阶段5亿美元左右的A+轮融资,2019年年底前完成7亿美元的Pre-IPO轮融资,2020IPO 区块链公司先行宣布将对FF进行投资.EVAIO(中文名:伊娃)公司 跨链 ...