hdu5296(倍增lca)
2015-08-27 15:27
381 查看
对于这道题,虽然题中有个求最小值,但它不是需要进行选择边的那种题,如果给定确定的点,把这些点连到一起,使得任意两点可达,那么只有一种方法(当然,去除掉多余的边,即叶子节点和根节点都必须在集合中)。所以可以每次加边时,只要找到一种方法,把它加入到已有树中就可以了,并且只有一种方法(当然,还是要去掉多余的边)。
至于根据dfs序找,假设要加入x这个点:
1)集合中有dfs序大于x的,并且也有小于x的,假设dfs序大于x的那个点是x的子节点,根据公式,可以的出,花费为0,余现实情况相符。
2)同1)中找出的两个点,只不过dfs序大于x的那个点不是x的子节点,那么此时必然离x最近的某个祖先节点虽然没在集合中,但是也己经在那个前几步生成的树当中,此时,只要把x到这个祖父节点的距离找出来,就是最小花费。根据公式所求,符合现实情况。
3)如果集合中不同时存在dfs序大于x的,和dfs序小于x的,假设,选出的此时集合中dfs序最大和最小的点,都是x的子节点,根据公式所求,符合现实要求。
4)选点同3,只是选出的两个点都是dfs序小于x的,那么如果此时这两个点的最近公共祖先是x的祖先节点,按照公式所求,符合现实要求,如果不是,按照公式所求,符合现实要求。
5)选点同3,只是选出的两个点都是dfs序大于x的,并且都不是x的子节点,同4
6)选点同3,只是选出的两个点都是dfs序大于x的,一个是x的子节点,一个不是x的子节点,按照公式所求,符合现实要求。
至于那道题,怎么正着推出这道题的解,现在只能把它当做一个结论来记了。
假设节点要连接到一个链中,链的定点(x,y),那么u连接到x的距离是dfn[u] + dfn[x] - 2dfn[ lca(u,x) ] ;
u连接到y的距离dfn[u] + dfn[y] - 2dfn[ lca(u,x) ] :
x连接到y的距离dfn[x] + dfn[y] - 2dfn[ lca(x,y) ] :
u连接到x-y这个链的距离 = (u到y+u到x-x到y)/2
迭代器讲解链接:http://www.cnblogs.com/yc_sunniwell/archive/2010/06/25/1764934.html
代码参考链接:http://www.bubuko.com/infodetail-988787.html
set的链接:http://baike.baidu.com/link?url=Uxof9XTaQURDJ9H8vSaVz4Cs8SOqee2kHyj37CBr2GrLzj-IqYGI5PGyBonm5C_oRWeBBbBbzfGDdlByuw1owK
用的是倍增lca。
(听说今天学校其余食堂就开门了,一共7个食堂,假期就开了4个,但是关的那三个中偏偏又两个常去的,开的这4个中虽然有两个个平常会去的,但是其中有一个,经常吃的窗口关了,所以这个暑假的食堂好凄惨!
)
2015.8.31:
这道题也是刚做不久,回忆了一下过程,还沥沥在目!
至于根据dfs序找,假设要加入x这个点:
1)集合中有dfs序大于x的,并且也有小于x的,假设dfs序大于x的那个点是x的子节点,根据公式,可以的出,花费为0,余现实情况相符。
2)同1)中找出的两个点,只不过dfs序大于x的那个点不是x的子节点,那么此时必然离x最近的某个祖先节点虽然没在集合中,但是也己经在那个前几步生成的树当中,此时,只要把x到这个祖父节点的距离找出来,就是最小花费。根据公式所求,符合现实情况。
3)如果集合中不同时存在dfs序大于x的,和dfs序小于x的,假设,选出的此时集合中dfs序最大和最小的点,都是x的子节点,根据公式所求,符合现实要求。
4)选点同3,只是选出的两个点都是dfs序小于x的,那么如果此时这两个点的最近公共祖先是x的祖先节点,按照公式所求,符合现实要求,如果不是,按照公式所求,符合现实要求。
5)选点同3,只是选出的两个点都是dfs序大于x的,并且都不是x的子节点,同4
6)选点同3,只是选出的两个点都是dfs序大于x的,一个是x的子节点,一个不是x的子节点,按照公式所求,符合现实要求。
至于那道题,怎么正着推出这道题的解,现在只能把它当做一个结论来记了。
假设节点要连接到一个链中,链的定点(x,y),那么u连接到x的距离是dfn[u] + dfn[x] - 2dfn[ lca(u,x) ] ;
u连接到y的距离dfn[u] + dfn[y] - 2dfn[ lca(u,x) ] :
x连接到y的距离dfn[x] + dfn[y] - 2dfn[ lca(x,y) ] :
u连接到x-y这个链的距离 = (u到y+u到x-x到y)/2
迭代器讲解链接:http://www.cnblogs.com/yc_sunniwell/archive/2010/06/25/1764934.html
代码参考链接:http://www.bubuko.com/infodetail-988787.html
set的链接:http://baike.baidu.com/link?url=Uxof9XTaQURDJ9H8vSaVz4Cs8SOqee2kHyj37CBr2GrLzj-IqYGI5PGyBonm5C_oRWeBBbBbzfGDdlByuw1owK
用的是倍增lca。
(听说今天学校其余食堂就开门了,一共7个食堂,假期就开了4个,但是关的那三个中偏偏又两个常去的,开的这4个中虽然有两个个平常会去的,但是其中有一个,经常吃的窗口关了,所以这个暑假的食堂好凄惨!
)
2015.8.31:
这道题也是刚做不久,回忆了一下过程,还沥沥在目!
#include<stdio.h> #include<string.h> #include<iostream> #include<set> using namespace std; #define N 100010 #define M 20 int deep ,dis ; int vis ; int head ,to[2*N],nextedge[2*N],wedge[2*N]; int dfsxv ,dfsxf ; int fadp [M]; set<int> s; set<int>::iterator iter; int cou; int time; void add(int a,int b,int c){ to[cou]=b;nextedge[cou]=head[a];wedge[cou]=c;head[a]=cou++; } void dfs(int u,int fa){ dfsxv[u]=++time; dfsxf[time]=u; for(int i=head[u];i!=-1;i=nextedge[i]){ int v=to[i]; if(v==fa){ continue; } else{ deep[v]=deep[u]+1; dis[v]=dis[u]+wedge[i]; fadp[v][0]=u; for(int j=1;(1<<j)<deep[v];j++){ fadp[v][j]=fadp[fadp[v][j-1]][j-1]; } dfs(v,u); } } return; } int lca(int a,int b){ if(deep[a]<deep[b]){ swap(a,b); } int tempi; for(tempi=0;(1<<tempi)<deep[a];tempi++); tempi--; for(int i=tempi;i>=0;i--){//使得合理答案永远在(a,a+2*tempi-1)的范围内 if(deep[fadp[a][i]]>=deep[b]){ a=fadp[a][i]; } } if(a==b){ return a; } for(tempi=0;(1<<tempi)<deep[a];tempi++); tempi--; for(int i=tempi;i>=0;i--){//是的合理答案,一直在(a+1,a+2*tempi)的范围内 if(fadp[a][i]!=fadp[b][i]){ a=fadp[a][i]; b=fadp[b][i]; } } return fadp[a][0];//尝试:在上面的循环中去掉i=0.->不能去掉i=0 } int solve(int u){ if(s.size()==0){ return 0; } else{ int x,y; iter=s.lower_bound(dfsxv[u]); if(iter==s.end()||iter==s.begin()){ x=dfsxf[*s.begin()];//注意* y=dfsxf[*s.rbegin()]; } else{ x=dfsxf[*iter]; iter--; y=dfsxf[*iter]; } return dis[u]+dis[lca(x,y)]-dis[lca(u,x)]-dis[lca(u,y)]; } } int main(){ int t; int n,q; int a,b,c; scanf("%d",&t); for(int cas=1;cas<=t;cas++){ scanf("%d%d",&n,&q); memset(head,-1,sizeof(head)); cou=0; for(int i=1;i<n;i++){ scanf("%d%d%d",&a,&b,&c); add(a,b,c); add(b,a,c); } memset(fadp,0,sizeof(fadp));//要是0,而不是1 deep[0]=-1; deep[1]=1; dis[1]=0; time=0; dfs(1,-1); memset(vis,0,sizeof(vis)); s.clear();//如果用容器什么的,也要考虑清理 int ans=0; printf("Case #%d:\n",cas); for(int i=0;i<q;i++){ scanf("%d%d",&a,&b); if(a==1){ if(!vis[b]){ vis[b]=1; ans+=solve(b); s.insert(dfsxv[b]); } } else if(a==2){ if(vis[b]){ vis[b]=0; s.erase(dfsxv[b]); ans-=solve(b); } } printf("%d\n",ans); } } return 0; }
相关文章推荐
- mysql挿入数据中文乱码问题
- 链式队列
- 单链表的插入和遍历 包括头插入和尾插入
- hdu5296(倍增lca)
- Linux系统——提高编译速度的方法
- 【转】C#模拟http 发送post或get请求
- DTD Content model definitions
- java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory
- Ubuntu无法进入mysql,报ERROR 2002 (HY000): Can't connect to local MySQL server through socket …错误
- intel驱动包下载
- HTML5之自定义标签(之前都没用过这么6的技术)
- linux进程——后台运行的方法
- 一个SQLSERVER触发器的示例
- Install ffmpeg on CentOS (RHEL/Fedora)
- UTF-8简史
- 今年暑假不AC
- 5. jQuery 效果 - 隐藏和显示
- 通过工具来监控webService请求和返回时的数据
- iOS导航页
- 说说耦合(coupling)