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. Linux--Shell基本运算符

    参考:http://www.runoob.com/linux/linux-shell-basic-operators.html

  2. Cisco连接失败问题处理

    连接公司的VPN时软件一直安装不上,试了几种方法,在此总结. 原文链接:http://www.itsystemadmin.com/error-27850-unable-to-manage-networ ...

  3. GitHub的学习和使用

    大二寒假阶段: 今天初学了GitHub,并下载了git base,在如下大佬给的链接下并完成了新用户的注册以及项目的上传学习. 网站的新用户注册界面:                https://g ...

  4. JDK11 JAVA11下载安装与快速配置环境变量教程

    https://blog.csdn.net/weixin_40928253/article/details/83590136 1.到Oracle官网下载jdk11,并安装.搜索“jdk",选 ...

  5. 合并两个django的queryset

    有queryset:A和B 要合并它们,根据网上的答案,貌似是用itertools库的chain对象比较好,地址 c=chain(x,y)   但是当c用于分页的时候,就有问题,会报chain没有le ...

  6. CodeForces 382B 数学推导

    这个题目题意简单,但是TLE得哭哭的... 输入 a b w x c五个数,最终要使得c<=a, 每一秒可以进行一个操作,如果b>=x,则 b=b-x,同时 c--;如果b<x,则a ...

  7. Tensorflow学习教程------下载图像识别模型inceptionV3

    # coding: utf-8 import tensorflow as tf import os import tarfile import requests #inception模型下载地址 in ...

  8. Maven--传递性依赖和依赖范围

    依赖范围不仅可以控制依赖与三种 classpath 的关系,还对传递性依赖产生影响. 假设 A 依赖于 B,B依赖于 C,我们说 A 对于 B 是第一直接依赖,B 对于 C 是第二直接依赖,A 对于 ...

  9. 如何把word文档导入到数据库中——java POI

    本文方法借鉴于https://www.cnblogs.com/ljysy/p/10574197.html 在经过朋友的指导下,在处理文档的方式上有所不同. 我的数据库使用的是SQL server,这篇 ...

  10. 题解-------[ZJOI2009]对称的正方形

    传送门 题目大意 找到所有的上下左右都相同的正方形. 思路:二分+二维Hash 这道题我们首先想到不能暴力判断一个正方形是否合法. 然后我们发现当一个正方形合法时,以这个正方形为中心且比它小的正方形也 ...