HDU 5296 Annoying problem (LCA,变形)
2015-07-22 14:24
183 查看
题意:
给一棵n个节点的树,再给q个操作,初始集合S为空,每个操作要在一个集合S中删除或增加某些点,输出每次操作后:要使得集合中任意两点互可达所耗最小需要多少权值。(记住只能利用原来给的树边。给的树边已经有向。10万个点,10万个操作)
思路:只能用 O(nlogn)的复杂度。官方题解:
AC代码
给一棵n个节点的树,再给q个操作,初始集合S为空,每个操作要在一个集合S中删除或增加某些点,输出每次操作后:要使得集合中任意两点互可达所耗最小需要多少权值。(记住只能利用原来给的树边。给的树边已经有向。10万个点,10万个操作)
思路:只能用 O(nlogn)的复杂度。官方题解:
#include <bits/stdc++.h> #define LL long long #define pii pair<int,int> #define INF 0x7f7f7f7f using namespace std; const int N=100100; vector<int> chld ; //孩子 unordered_map<int,int> weight ; int dis ; int mapp ; int seq ; //seq记录DFS序 int anti_seq ; //anti记录第几个访问的是谁 bool inset ; int ans, num; set<int> sett; void DFS(int x) { seq[x]=++num; for(int i=0; i<chld[x].size(); i++) { int t=chld[x][i]; if(!seq[t]) DFS(t); } } unordered_map<int,int> vis; int LCA(int a,int b) { vis.clear(); while(mapp[a]) { vis[a]=1; a=mapp[a]; } vis[a]=1; while( !vis[b] ) b=mapp[b]; return b; } void cal_weight(int n) { for(int i=1; i<=n; i++) { int sum=0, s=i; while(mapp[s]) { sum+=weight[mapp[s]][s]; s=mapp[s]; } dis[i]=sum; } } int ins(int u) { sett.insert(seq[u]); if(sett.size()==1) {ans=0;return 0;} set<int>::iterator it=sett.find(seq[u]); int x=0, y=0; if(*it==*sett.begin()) //已经是最小 { x=anti_seq[*(++it)]; y=anti_seq[*(sett.rbegin())]; } else if(*it==*sett.rbegin()) //已经是最大 { x=anti_seq[*(--it)]; y=anti_seq[*(sett.begin())]; } else { x=anti_seq[ *(--it)]; y=anti_seq[ *(++(++it)) ]; } ans+=dis[u]-dis[LCA(u,x )]- dis[LCA(u,y )] + dis[LCA(x,y)]; return ans; } int del(int u) { if(sett.size()==2) { sett.erase(seq[u]); ans=0; return 0; } set<int>::iterator it=sett.find(seq[u]); int x=0, y=0; if(*it==*sett.begin()) //已经是最小 { x=anti_seq[*(++it)]; y=anti_seq[*(sett.rbegin())]; } else if(*it==*sett.rbegin()) //已经是最大 { x=anti_seq[*(--it)]; y=anti_seq[*(sett.begin())]; } else { x=anti_seq[ *(--it)]; y=anti_seq[ *(++(++it)) ]; } ans-=dis[u]-dis[LCA(u,x )]- dis[LCA(u,y )] + dis[LCA(x,y)]; sett.erase(seq[u]); return ans; } int main() { freopen("input.txt", "r", stdin); int a, b, c, t, q, n, j=0; cin>>t; while(t--) { scanf("%d%d", &n, &q); for(int i=0; i<=n+10; i++) chld[i].clear(),weight[i].clear(); memset(inset, 0, sizeof(inset)); memset(seq, 0, sizeof(seq)); memset(anti_seq, 0, sizeof(anti_seq)); memset(mapp, 0, sizeof(mapp)); memset(dis,0,sizeof(dis)); sett.clear(); ans=0; num=0; for(int i=1; i<n; i++) { scanf("%d%d%d",&a,&b,&c); chld[a].push_back(b); weight[a][b]=c; mapp[b]=a; } printf("Case #%d:\n",++j); int root=n; //获得树根 while(mapp[root]) root=mapp[root]; DFS(root); //获得DFS序 for(int i=1; i<=n; i++) anti_seq[seq[i]]=i; //反向索引 cal_weight(n); //计算每个点到根的权 while(q--) { scanf("%d%d",&a,&b); if(a==1) //如果不存在于集合中,则插,有则不插 { if(inset[b]) printf("%d\n", ans); //已经存在,不必计算 else { inset[b]=1; printf("%d\n", ins(b)); } } else //如果存在于集合中,则删,否则不删。 { if(inset[b]) //存在,要删 { inset[b]=0; printf("%d\n",del(b)); } else printf("%d\n",ans); } } } return 0; }
AC代码
相关文章推荐
- TCP/IP详解学习笔记(9)-TCP协议概述
- session和cookie的联系
- uva 439 Knight Moves 骑士移动
- 前端json数据排序
- Delphi连接Oracle控件ODAC的安装及使用
- 获取cell在屏幕中的位置
- jquery怎么跳出当前的each循环
- Android 动画
- javaWeb最全的文件上传下载
- Java开发环境配置方法
- CALayer与UIView的关系
- Ruby 中的inject方法
- mybatis入门——实例
- struts-tags在哪个包下
- POI&JXL用法及区别
- NSUserDefaults保存用户名和密码
- boost Windows x64 编译
- 2012年5月SAT香港真题解析
- 获取键盘的高度
- error LNK2019: unresolved external symbol "__declspec(dllimport) const CReadUserInfo::`vftable'" (__