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. 给普通用户加sudo权限

    系统环境:centos 7.0 引文:在实验室的服务器上给每个人分配了一个账号,但是有的时候普通用户需要使用root权限,比如装一些软件之类的.下面介绍怎么给普通用户添加sudo命令权限. 前提: s ...

  2. 阿里云服务器centos下安装配置svn服务器

      阿里云服务器centos下安装配置svn服务器 1.安装svn服务器端yum install subversion      从镜像下载安装svn服务器端中间会提示是否ok,输入y,确认安装成功提 ...

  3. 更新anaconda包

    升级安装python环境后, 把老的包重新安装回去. ls -l /opt/anaconda3/lib/python3.7/site-packages/ | grep "\-info&quo ...

  4. paddle(一)

    一.概述 一个机器学习的框架,提供了深度学习需要的神经网络,激活函数等主要功能. 基础概念 Program 一次模型训练就是一个program,通过执行器执行,默认环境下是执行fluid.defaul ...

  5. python 爬虫 多线程 多进程

    一.程序.进程和线程的理解  程序:就相当于一个应用(app),例如电脑上打开的一个程序. 进程:程序运行资源(内存资源)分配的最小单位,一个程序可以有多个进程. 线程:cpu最小的调度单位,必须依赖 ...

  6. one_day_one_linuxCmd---scp命令

    <坚持每天学习一个 linux 命令,今天我们来学习 scp 命令> scp 命令主要用在不同的 linux 系统之间 copy 文件,基于 ssh 登录,是一种安全的复制 scp 命令的 ...

  7. C - Monitor CodeForces - 846D (二维前缀和 + 二分)

    Recently Luba bought a monitor. Monitor is a rectangular matrix of size n × m. But then she started ...

  8. 运行SQL文件报错Invalid ON UPDATE clause for 'create_date' column

    Invalid ON UPDATE clause for 'create_date' column   原因: 高版本的mysql导数据到低版本出现的问题 日期类型报错 MySQL 5.5 每个表只允 ...

  9. 最大连续子序列(DP)

    Description 给定K个整数的序列{ N1, N2, ..., NK },其任意连续子序列可表示为{ Ni, Ni+1, ..., Nj },其中 1 <= i <= j < ...

  10. 6)PHP,预定义变量

    预定义变量也叫超全局变量: :预定义变量又叫超全局变量,包括: $_GET, $_POST, $_SERVER, $_REQUEST, $GLOBALS, $_COOKIE, $_SESSION, . ...