hdu5296
来源:互联网 发布:越狱苹果抹除所有数据 编辑:程序博客网 时间:2024/06/06 19:08
题意:给定一颗边权树,动态地在点集中增加和删除点。求当前所在点集中使得所有点都连通的最小边权和。
解法:
首先介绍一个结论:
树上点u到以x和y为端点的链的最段距离可以在O(n)预处理和O(logn)时间复杂度内求出。
证明:设z=lca(x,y),dis[u]为树中点u到跟节点的路径权值和。则dis< u,(x,y) >=dis[u]-dis[lca(u,x)]-dis[lca(u,y)]+dis[z]。lca均可在O(logn)内求出,得证!
推论如下:
判断树上某点u是否在链(x,y)上可以在O(logn)复杂度内求出
求dis< u,(x,y) >,结果为0则在链(x,y)上,反之不在。
求链(x1,y1)和链(x2,y2)的最段距离可以在O(logn)复杂度内求出
设z1=lca(x1,y1),z2=lca(x2,y2),不妨设z1高度更高。则z2到(x1,y1)距离即为链(x2,y2)到(x1,y2)距离
另一个结论是:
树中一系列点的lca和dfs序最小和最大的点的lca相同
该结论等价于定点u和动点v的lca随v的dfs序增大而不减。这个结论很显然通过v的移动可以看出确实如此。
回到本题。先求树中每点的dfs序。如果添加的点u在已知点集中存在dsf序比它小的最大点x和dfs序比它大的最小点y,那么增加的权值和即为u到达链(x,y)的距离,这个结论可以通过实验x和y的不同相对位置得到;如果所有点的dfs序都比y的dfs序大或小,那么只要求出dfs序的最大和最小值对应顶点x和y,求u到链(x,y)距离即可,这可以由上述结论证明正确性。
#include<stdio.h>#include<string.h>#include<iostream>#include<vector>#include<math.h>#include<set>#include<algorithm>#define ll intusing namespace std;const int maxn = 100000+10;int t,n,q;struct Edge{ int to,w,next;}edge[maxn<<2];int head[maxn],tot;void add(int u,int v,int w) { edge[tot].to=v,edge[tot].w=w,edge[tot].next=head[u],head[u]=tot++; }int father[maxn], fa[maxn][20+3], deep[maxn];bool vis[maxn];int dis[maxn],dfst[maxn],dfs_clock,id[maxn];int tmpans;set<int> se;set<int>::iterator iter;void dfs(int u,int f) { deep[u] = deep[f]+1; father[u]=f; dfst[u]=++dfs_clock; id[dfs_clock]=u; for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].to,w=edge[i].w;; if(v==f) continue; dis[v]=dis[u]+w; dfs(v,u); }}void init() { deep[0]=0,dis[1]=0,dfs_clock=0; dfs(1,0); for(ll i=1;i<=n;i++) fa[i][0]=father[i]; for(ll j=1;j<=18;j++) for(ll i=1;i<=n;i++) fa[i][j]=fa[fa[i][j-1]][j-1];}int lca(int x,int y) { if (deep[x] < deep[y]) swap(x, y); int delta = deep[x] - deep[y]; for(int j=0;j<=18;j++) if ((1<<j) & delta) x = fa[x][j]; if (x == y) return x; for(int j=18;j>=0;j--) if (fa[x][j] != fa[y][j]) x = fa[x][j], y = fa[y][j]; return fa[x][0];}int fun(int u){ if(!se.size()) return 0; iter=se.lower_bound(dfst[u]); int x,y; bool flag=false; if(iter!=se.end()){ y=*iter; y=id[y]; if(iter!=se.begin()){ iter--; x=*iter; x=id[x]; flag=true; } } if(!flag){ iter=se.begin(); x=*iter; x=id[x]; iter=se.end(); iter--; y=*iter; y=id[y]; } int tmp=dis[u]-dis[lca(u,x)]-dis[lca(u,y)]+dis[lca(x,y)]; return tmp;}int main(){ //freopen("a.txt","r",stdin); scanf("%d",&t); for(int cas=1;cas<=t;cas++){ scanf("%d%d",&n,&q); memset(head,-1,sizeof(head)); tot=0; memset(vis,0,sizeof(vis)); se.clear(); for(int i=1;i<n;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); add(u,v,w); add(v,u,w); } init(); tmpans=0; printf("Case #%d:\n",cas); for(int i=1;i<=q;i++){ int x,u; scanf("%d%d",&x,&u); if(x==1&&!vis[u]) { vis[u]=1; tmpans+=fun(u); se.insert(dfst[u]); } else if(x==2&&vis[u]) { vis[u]=0; se.erase(dfst[u]); tmpans-=fun(u); } printf("%d\n",tmpans); } } return 0;}
0 0
- hdu5296
- HDU5296
- hdu5296(倍增lca)
- hdu5296 Annoying problem
- hdu5296 01字典树
- hdu5296 Annoying problem (LCA+SET)
- hdu5296(2015多校1)--Annoying problem(lca+一个公式)
- HDU5296从一棵树上取出若干不连通的点
- Unity3d for android 访问UI控件报错 Can\'t create handler inside thread that has not called Looper.prepare()
- 抓取网页信息,下载网络图片到本地
- 太凶残了:程序员的终极复仇方式
- set使用
- 栈的概念
- hdu5296
- MFC学习笔记.day01-WINMAIN,MSG,WNDCLASS,ID-HANDLE-HWND,图标光标
- epoll介绍和使用
- Fast and accurate short read alignment with Burrows-Wheeler transform
- Java的基本数据类型全解(by 星空武哥)
- Ansible常用模块
- hdu 5289 Assignment (rmq模版)
- oc002---定义OC的类和创建OC的对象
- Hibernate建立多对一的单向关联关系