HDU-5957 Query on a graph(线段树+树剖)
来源:互联网 发布:linux启动.sh命令 编辑:程序博客网 时间:2024/06/09 17:03
Query on a graph
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 325 Accepted Submission(s): 73
We will ask you to perform some instructions of the following forms.
MODIFY u k d: weight of all nodes in S(u,k) increase by d or decrease by -d.
QUERY u k: ask for the sum of weight of all nodes in S(u,k).
In the beginning, the weight of all nodes are 0.
261 22 33 44 14 53 65MODIFY 1 1 3MODIFY 3 1 2MODIFY 5 2 1QUERY 3 2QUERY 4 161 22 33 11 42 53 65MODIFY 3 1 5MODIFY 2 2 2QUERY 6 1MODIFY 4 1 -2QUERY 2 2
21141428
题意:一个图有n个点,n条边(一定存在环,但没有自环和重边)
定义D(u,v)为u到v的距离,S(u,k)为所有D(u,v)<=k的节点v的集合
有m次询问(0<=k<=2):
①u k d:将集合S(u,k)的所有节点的权值加d
②u k:询问集合S(u,k)的所有节点的权值之和
题解:线段树
首先将图分为2个部分:1个环和若干棵树(每棵树的根节点在环上)
这一步可以通过拓扑排序完成
设val[u]为节点u的权值,fa[u]为父亲,son[u]为儿子,sson[u]孙子
根据k的取值分情况讨论:
①k = 0时
ans = val[u]
②k = 1时
1)u为树上节点:ans = ∑val[son[u]] + val[u] + val[fa[u]]
2)u为环上节点:ans = ∑val[son[u]] + val[u] + val[u在环上的邻居]
③k = 2时
设father = fa[u]
1)u为树上节点:ans = ∑val[son[u]] + ∑val[sson[u]] + val[father] + ∑val[son[father]]
(1)father为树上节点:ans += val[fa[father]]
(2)father为环上节点:ans += ∑val[father在环上的邻居]
2)u为环上节点:ans = ∑val[son[u]] + ∑val[sson[u]] + val[u在环上的邻居] + val[邻居的邻居] + ∑val[son[邻居]]
知道ans该怎么求解了,重点是怎么求和。逐个求和的话复杂度高达O(n^2)显然是不行的,因此需要
用线段树进行区间维护。我们可以知道,对一个棵树求BFS序后,深度相同的节点的序号是相邻的。
对于节点u,如果知道它儿子的最小BFS序号L和最大BFS序号R,那么它儿子的所有序号就在[L,R]中。
因此我们就有了维护权值的方法:类似于树链剖分,我们将所有节点都用BFS序编号并存入线段树,
如果要访问某个节点u的所有儿子,只要知道其序号区间[L,R],这个区间序号可以用sonL[u]和sonR[u]
维护,类似的u孙子的区间序号也可以用ssonL[u]和ssonR[u]存放
至此问题就解决了,由于用到线段树,总复杂度为O(mlogn)
#include<bits/stdc++.h>#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1using namespace std;typedef long long LL;const int MX = 1e5 + 5;const int INF = 0x3f3f3f3f;struct Edge{ int v,nxt;}E[MX*2];int head[MX],IN[MX],tot,n;void init_edge(){ for(int i=1;i<=n;i++) {IN[i]=0;head[i]=-1;} tot=0;}void add_edge(int u,int v){ E[tot].v=v; E[tot].nxt=head[u]; head[u]=tot++; IN[v]++;}void top_sort(){ queue<int>q; for(int i=1;i<=n;i++) if(IN[i]==1) q.push(i); while(!q.empty()){ int u=q.front();q.pop(); for(int i=head[u];~i;i=E[i].nxt){ int v=E[i].v; if(IN[v]>1){ IN[v]--; if(IN[v]==1) q.push(v); } } }}int p[MX],fp[MX],fa[MX],sz;int sonL[MX],sonR[MX],ssonL[MX],ssonR[MX];void bfs(int top){ queue<int>q; q.push(top); while(!q.empty()){ int u=q.front();q.pop(); sonL[u]=ssonL[u]=INF; sonR[u]=ssonR[u]=0; //printf("[%d %d]\n",u,p[u]); for(int i=head[u];~i;i=E[i].nxt){ int v=E[i].v; if(IN[v]>1||v==fa[u]) continue; p[v]=++sz; fp[sz]=v; fa[v]=u; sonL[u]=min(sonL[u],p[v]); sonR[u]=max(sonR[u],p[v]); q.push(v); } ssonL[fa[u]]=min(ssonL[fa[u]],sonL[u]); ssonR[fa[u]]=max(ssonR[fa[u]],sonR[u]); }}LL sum[MX<<2],add[MX<<2];void build(int l,int r,int rt){ sum[rt]=add[rt]=0; if(l==r) return; int m=(l+r)>>1; build(lson); build(rson);}void PushDown(int m,int rt){ if(add[rt]){ add[rt<<1]+=add[rt]; add[rt<<1|1]+=add[rt]; sum[rt<<1]+=add[rt]*(m-(m>>1)); sum[rt<<1|1]+=add[rt]*(m>>1); add[rt]=0; }}void PushUP(int rt){ sum[rt]=sum[rt<<1]+sum[rt<<1|1];}void update(int L,int R,int c,int l,int r,int rt){ if(L==0||R==0) return; if(L<=l&&R>=r){ sum[rt]+=(LL)(r-l+1)*c; add[rt]+=c; return; } PushDown(r-l+1,rt); int m=(l+r)>>1; if(L<=m) update(L,R,c,lson); if(R>m) update(L,R,c,rson); PushUP(rt);}LL query(int L,int R,int l,int r,int rt){ if(L==0||R==0) return 0; if(L<=l&&R>=r) return sum[rt]; PushDown(r-l+1,rt); int m=(l+r)>>1; LL ret=0; if(L<=m) ret+=query(L,R,lson); if(R>m) ret+=query(L,R,rson); PushUP(rt); return ret;}int ver[MX][2];void init(){ for(int i=1;i<=n;i++) fa[i]=0; sz=0;}void pre_solve(){ init(); top_sort(); for(int u=1;u<=n;u++) if(IN[u]>1){ int j=0; for(int i=head[u];~i;i=E[i].nxt){ int v=E[i].v; if(IN[v]>1) ver[u][j++]=v; } p[u]=++sz; fp[sz]=u; bfs(u); } build(1,n,1);}void solve_modify(int u,int k,int d){ int father=fa[u]; if(k==0) update(p[u],p[u],d,1,n,1); else if(k==1){ update(sonL[u],sonR[u],d,1,n,1); update(p[u],p[u],d,1,n,1); if(IN[u]==1) update(p[father],p[father],d,1,n,1); else{ for(int i=0;i<2;i++){ int v=ver[u][i]; update(p[v],p[v],d,1,n,1); } } } else{ update(sonL[u],sonR[u],d,1,n,1); update(ssonL[u],ssonR[u],d,1,n,1); if(IN[u]==1){ update(p[father],p[father],d,1,n,1); update(sonL[father],sonR[father],d,1,n,1); if(IN[father]==1) update(p[fa[father]],p[fa[father]],d,1,n,1); else{ for(int i=0;i<2;i++){ int v=ver[father][i]; update(p[v],p[v],d,1,n,1); } } } else{ update(p[u],p[u],d,1,n,1); int vv[2],cnt=0; for(int i=0;i<2;i++){ int v=ver[u][i]; update(p[v],p[v],d,1,n,1); update(sonL[v],sonR[v],d,1,n,1); for(int j=0;j<2;j++){ if(ver[v][j]==u||ver[v][j]==ver[u][0]||ver[v][j]==ver[u][1]) continue; if(cnt>0&&ver[v][j]==vv[cnt-1]) continue; vv[cnt++]=ver[v][j]; } } for(int i=0;i<cnt;i++){ update(p[vv[i]],p[vv[i]],d,1,n,1); } } }}LL solve_query(int u,int k){ int father=fa[u]; LL ret=0; if(k==0) ret+=query(p[u],p[u],1,n,1); else if(k==1){ ret+=query(sonL[u],sonR[u],1,n,1); ret+=query(p[u],p[u],1,n,1); if(IN[u]==1) ret+=query(p[father],p[father],1,n,1); else{ for(int i=0;i<2;i++){ int v=ver[u][i]; ret+=query(p[v],p[v],1,n,1); } } } else{ ret+=query(sonL[u],sonR[u],1,n,1); ret+=query(ssonL[u],ssonR[u],1,n,1); if(IN[u]==1){ ret+=query(p[father],p[father],1,n,1); ret+=query(sonL[father],sonR[father],1,n,1); if(IN[father]==1) ret+=query(p[fa[father]],p[fa[father]],1,n,1); else{ for(int i=0;i<2;i++){ int v=ver[father][i]; ret+=query(p[v],p[v],1,n,1); } } } else{ ret+=query(p[u],p[u],1,n,1); int vv[2],cnt=0; for(int i=0;i<2;i++){ int v=ver[u][i]; ret+=query(p[v],p[v],1,n,1); ret+=query(sonL[v],sonR[v],1,n,1); for(int j=0;j<2;j++){ if(ver[v][j]==u||ver[v][j]==ver[u][0]||ver[v][j]==ver[u][1]) continue; if(cnt>0&&ver[v][j]==vv[cnt-1]) continue; vv[cnt++]=ver[v][j]; } } for(int i=0;i<cnt;i++){ ret+=query(p[vv[i]],p[vv[i]],1,n,1); } } } return ret;}int main(){ //freopen("in.txt","r",stdin); int T,m,u,v,k,d; char op[10]; scanf("%d",&T); while(T--){ scanf("%d",&n); init_edge(); for(int i=1;i<=n;i++){ scanf("%d%d",&u,&v); add_edge(u,v);add_edge(v,u); } pre_solve(); scanf("%d",&m); while(m--){ scanf("%s",op); if(op[0]=='M'){ scanf("%d%d%d",&u,&k,&d); solve_modify(u,k,d); } else { scanf("%d%d",&u,&k); printf("%lld\n",solve_query(u,k)); } } } return 0;}
- HDU-5957 Query on a graph(线段树+树剖)
- 【HDU】5957 Query on a graph【分类讨论+bfs序线段树】
- [bfs序 线段树] HDU5957. Query on a graph
- 【HDU】3804 Query on a tree dfs+线段树
- Hdu 3804 Query on a tree 树链剖分+线段树
- 【HDU】4677 Query on Graph 动态树
- HDU 4677 Query on Graph
- hdu 4677 Query on Graph
- SPOJ 375 Query on a tree (树链剖分+线段树)
- SPOJ Query on a tree (树链剖分 + 线段树)
- 计蒜客 Query on a string (线段树)
- SPOJ QTREE Query on a tree(树链剖分+线段树)
- Query on a string【线段树】
- 计蒜客 Query on a string 线段树
- Query on a string 线段树
- HDU 3804Query on a tree 树链剖分 + 线段树离线操作 好题
- SPOJ - QTREE 375 Query on a tree 树链剖分+线段树
- 【线段树】CSU 1414 Query on a Tree
- HDOJ2028求n个数的最小公倍数
- Combined Character
- 关于TexturePacker中 Allow free sizes的问题
- Java 对Java24种设计模式的想法和理解
- 一次搞定"=="和equals(),含源码解析
- HDU-5957 Query on a graph(线段树+树剖)
- JDBC通过Statement执行操作
- js获取当前时间,日期格式为年月日
- winform下调用SharpSSH库实现对远程linux主机的控制
- 一起来讨论讨论Java多线程技术-20170713
- sql select ... as...语法
- shell模拟程序消耗CPU资源
- HANA 如何创建XS Job来完成定时任务
- 常用计算机接口比较-crazy-bird