博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Codeforces 916E(思维+dfs序+线段树+LCA)
阅读量:5008 次
发布时间:2019-06-12

本文共 4537 字,大约阅读时间需要 15 分钟。

题面

题目大意:给定初始根节点为1的树,有3种操作
1.把根节点更换为r
2.将包含u,v的节点的最小子树(即lca(u,v)的子树)所有节点的值+x
3.查询v及其子树的值之和

分析

看到批量修改子树,我们想到将树上操作转化为区间操作

通过DFS序我们可以实现这一点.
对于每个节点x,我们记录它在前序遍历中的位置l[x],再一次回到x时的序号r[x],则x及其子树的区间为前序遍历中的[l[x],r[x]]
具体可点击

那么,3种操作如何进行:

操作1.用一个变量root记录当前根即可,时间复杂度O(1)O(1)
以下求LCA,DFS序,子树,以及修改等操作都在初始的树上进行,再想办法将它转换为根不是1的情况
操作2.由于根节点变化,需要分类讨论
首先,定义三个点的LCA值lca(u,v,w)为lca(u,v),lca(u,w),lca(v,w)中深度最深的那一个
设修改的点为u,v,根节点为root
(1) 若lca(u,v)在root的子树中
这里写图片描述
显然结果和根为1的情况一样,直接修改即可,时间复杂度O(log2n)O(log2n)

(2)若lca(u,v,root)=root

这里写图片描述
很明显包含u,v的最小子树就是整棵树,所以修改整棵树,时间复杂度O(log2n)O(log2n)

(3)若root在lca(u,v,root)的子树中

这里写图片描述
此时可采用类似容斥原理的方法
先将整棵树的值+x
再找到root的祖先中离lca(u,v,root)最近的整数w,将w及其子树(绿色部分)的值-x,剩下的就是包含u,v的最小子树了(黄色部分)
求w可用树上倍增,时间复杂度O(log2n)O(log2n)

操作3.

类似操作2的分类讨论
设查询的点为u,根节点为root
(1)若u在root的子树中,则直接查询u的子树
(2)若u=root,查询整棵树
(3)若root在u的子树中
这里写图片描述
先查询整棵树的值之和,再找root的祖先中距离u最近的一个v
用整棵树的值之和-v及子树的值之和(绿色部分)=所求(黄色部分)

代码

#include
#include
#include
#include
#define maxn 100005#define maxlog 32using namespace std;inline int qread(){ int x=0,sign=1; char c=getchar(); while(c<'0'||c>'9'){ if(c=='-') sign=-1; c=getchar(); } while(c>='0'&&c<='9'){ x=x*10+c-'0'; c=getchar(); } return x*sign;}int n,q;int a[maxn];int root=1;struct edge{ int from; int to; int next;}E[maxn<<1];int head[maxn];int size=0;void add_edge(int u,int v){ size++; E[size].from=u; E[size].to=v; E[size].next=head[u]; head[u]=size;}int cnt;int log2n;int l[maxn],r[maxn];int deep[maxn],anc[maxn][maxlog];void dfs(int x,int fa){ l[x]=++cnt; anc[x][0]=fa; for(int i=1;i<=log2n;i++){ anc[x][i]=anc[anc[x][i-1]][i-1]; } for(int i=head[x];i;i=E[i].next){ int y=E[i].to; if(y!=fa){ deep[y]=deep[x]+1; dfs(y,x); } } r[x]=cnt;}int lca(int x,int y){ if(deep[x]
=0;i--){ if(deep[anc[x][i]]>=deep[y]){ x=anc[x][i]; } } if(x==y) return x; for(int i=log2n;i>=0;i--){ if(anc[x][i]!=anc[y][i]){ x=anc[x][i]; y=anc[y][i]; } } return anc[x][0];}int tri_lca(int u,int v,int r){ int l1=lca(u,v); int l2=lca(u,r); int l3=lca(v,r); int max_deep=max(deep[l1],max(deep[l2],deep[l3])); if(deep[l1]==max_deep) return l1; else if(deep[l2]==max_deep) return l2; else return l3;}int get_close(int w,int r){ int x=r; for(int i=log2n;i>=0;i--){ if(deep[anc[x][i]]>deep[w]){ x=anc[x][i]; } } return x;}struct node{ int l; int r; long long v; long long mark; int len(){ return r-l+1; }}tree[maxn<<2];void push_up(int pos){ tree[pos].v=tree[pos<<1].v+tree[pos<<1|1].v;}void build(int l,int r,int pos){ tree[pos].l=l; tree[pos].r=r; tree[pos].v=0; tree[pos].mark=0; if(l==r) return; int mid=(l+r)>>1; build(l,mid,pos<<1); build(mid+1,r,pos<<1|1); }void push_down(int pos){ if(tree[pos].mark){ tree[pos<<1].mark+=tree[pos].mark; tree[pos<<1|1].mark+=tree[pos].mark; tree[pos<<1].v+=tree[pos].mark*tree[pos<<1].len(); tree[pos<<1|1].v+=tree[pos].mark*tree[pos<<1|1].len(); tree[pos].mark=0; }}void update(int L,int R,long long v,int pos){ if(L<=tree[pos].l&&R>=tree[pos].r){ tree[pos].mark+=v; tree[pos].v+=(v*tree[pos].len()); return; } push_down(pos); int mid=(tree[pos].l+tree[pos].r)>>1; if(L<=mid) update(L,R,v,pos<<1); if(R>mid) update(L,R,v,pos<<1|1); push_up(pos);}long long query(int L,int R,int pos){ if(L<=tree[pos].l&&R>=tree[pos].r){ return tree[pos].v; } push_down(pos); int mid=(tree[pos].l+tree[pos].r)>>1; long long ans=0; if(L<=mid) ans+=query(L,R,pos<<1); if(R>mid) ans+=query(L,R,pos<<1|1); return ans;}void change(int u,int v,int x){ int xx=lca(u,v); int lca_num=tri_lca(u,v,root); if(l[root]
r[xx]){ update(l[xx],r[xx],x,1); return; }else if(lca_num==root){ update(1,n,x,1); return; }else{ int w2=get_close(lca_num,root); update(1,n,x,1); update(l[w2],r[w2],-x,1); return; }}long long sum(int w){ if(l[root]
r[w]){ return query(l[w],r[w],1); }else{ if(w==root){ return query(1,n,1); } int sonw=get_close(w,root);// printf("%d\n",query(1,n,1));// printf("%d\n",query(l[sonw],r[sonw],1)); return query(1,n,1)-query(l[sonw],r[sonw],1); }}int main(){ int u,v,cmd,x; n=qread(); q=qread(); for(int i=1;i<=n;i++) a[i]=qread(); for(int i=1;i

转载于:https://www.cnblogs.com/birchtree/p/9845829.html

你可能感兴趣的文章
综合练习:词频统计
查看>>
Ubuntu 安装Guake
查看>>
中文url编码乱码问题归纳整理一
查看>>
Ruby
查看>>
安装PowerDesigner 12之后,在Microsoft Office Word 2003的模板和插件中无法移除WordToRqm.dot的解决方案...
查看>>
Daily Scrum 12.12
查看>>
Cesium应用篇:3控件(3)SelectionIndicator& InfoBox
查看>>
58. Length of Last Word(js)
查看>>
前端面试题汇总(持续更新...)
查看>>
如何成为F1车手?
查看>>
QT自定义消息
查看>>
Save (Not Permitted) Dialog Box
查看>>
装饰模式(Decorator)
查看>>
3-11
查看>>
任务13:在Core Mvc中使用Options
查看>>
利用Excel 2010数据透视图实现数字的可视化的图形直观展示
查看>>
Sort Colors
查看>>
HTML文本框水印
查看>>
2048记录反查(ruby)
查看>>
用ssh整合时,用sessionfactory的getCurrentSession()获取不到session
查看>>