用dfs序处理线段树的好题吗?
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序处理线段树的好题吗?的更多相关文章
- bzoj3306: 树(dfs序+倍增+线段树)
比较傻逼的一道题... 显然求子树最小值就是求出dfs序用线段树维护嘛 换根的时候树的形态不会改变,所以我们可以根据相对于根的位置分类讨论. 如果询问的x是根就直接输出整棵树的最小值. 如果询问的x是 ...
- bzoj2819 DFS序 + LCA + 线段树
https://www.lydsy.com/JudgeOnline/problem.php?id=2819 题意:树上单点修改及区间异或和查询. 思维难度不高,但是题比较硬核. 整体思路是维护每一个结 ...
- 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 ...
- 7月13日考试 题解(DFS序+期望+线段树优化建图)
T1 sign 题目大意:给出一棵 N 个节点的树,求所有起点为叶节点的有向路径,其 上每一条边权值和的和.N<=10000 水题.考试的时候毒瘤出题人(学长orz)把读入顺序改了一下,于是很多 ...
- hdu 3974 Assign the task(dfs序上线段树)
Problem Description There is a company that has N employees(numbered from 1 to N),every employee in ...
- Luogu P2982 [USACO10FEB]慢下来 Slowing down | dfs序、线段树
题目链接 题目大意: 有一棵N个结点树和N头奶牛,一开始所有奶牛都在一号结点,奶牛们将按从编号1到编号N的顺序依次前往自己的目的地,求每头奶牛在去往自己目的地的途中将会经过多少已经有奶牛的结点. 题解 ...
- Codeforces Round #200 (Div. 1) D. Water Tree(dfs序加线段树)
思路: dfs序其实是很水的东西. 和树链剖分一样, 都是对树链的hash. 该题做法是:每次对子树全部赋值为1,对一个点赋值为0,查询子树最小值. 该题需要注意的是:当我们对一棵子树全都赋值为1的 ...
- hdu4366 Successor (dfs序+zkw线段树)
Successor Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total S ...
- URAL 1890 . Money out of Thin Air (dfs序hash + 线段树)
题目链接: URAL 1890 . Money out of Thin Air 题目描述: 给出一个公司里面上司和下级的附属关系,还有每一个人的工资,然后有两种询问: 1:employee x y z ...
随机推荐
- Aras Innovator如何配置SMTP中转Office365
参考文档:http://www.ebdadvisors.com/blog/2015/7/31/configure-an-smtp-server-in-windows-iis-for-aras-inno ...
- SEO初步学习之新站优化
新站优化技巧:新站有两个月扶持期,在扶持期间仅做一件事,提交大量优质受众的原创,且内容为不间断,即每天定点定量发布文章,使得蜘蛛对网站形成爬行习惯,新站初期内容为王,优化为辅. 虽说优化为辅,却不可或 ...
- LINUX的ssh免密码配置
本篇将介绍LINUX的ssh免密码配置. 本篇中的有三台主机: 192.168.1.110 master.com.cn 主机192.168.1.111 salver1.com.cn192.168.1 ...
- .NET 请求认证之access-token(oauth2.0与owin的结合)
公司对外开放的接口,大多需要请求认证,如微信,阿里等.最近我刚好在搭建webapi框架.记录一下自己的理解. 一:请求认证的目的 之所以要对我们的接口进行请求认证,就是为了安全考虑的.以前都是在用 ...
- 17.3.12---urlparse模块的URL下载
1---urlparse模块是一个解析与泛解析Web网址URL字符串的一个工具 urlparse模块会将一个普通的url解析为6个部分,返回的数据类型都是元祖,同时,他还可以将已经分解后的url在组合 ...
- MySQL和Java数据类型对照表
Java MySQL数据类型对照 类型名称 显示长度 数据库类型 JAVA类型 JDBC类型索引(int) 描述 VARCHAR L+N VARCHAR java.lang.S ...
- 洛谷 P3811 【模板】乘法逆元(欧拉定理&&线性求逆元)
题目传送门 逆元定义 逆元和我们平时所说的倒数是有一定的区别的,我们平时所说的倒数是指:a*(1/a) = 1,那么逆元和倒数之间的区别就是:假设x是a的逆元,那么 a * x = 1(mod p), ...
- GetTextExtentPoint32
/////////////////////////////////////////////////////////////// // 04FirstWindow.cpp文件 #include < ...
- Django_JavaScript
JavaScript是什么 JavaScript是一种运行在客户端(浏览器)的编程语言,用来给网页添加动态功能. JavaScript的作用 最初目的 为了处理表单的验证操作 现在广泛的应用场景 网页 ...
- 磁力搜索导航,MagnetW将搜索结果格式化统一显示
简介 magnetW基于magnetX的规则原理,将各个磁力站的搜索结果统一格式化 安装 从Github Releases或者Github Wiki下载对应平台 3.1.1 更新了一批规则 支持Soc ...