LCT(GCD Tree,HDU 5398)
来源:互联网 发布:windows svn 钩子 编辑:程序博客网 时间:2024/04/25 20:38
值得注意的是,千万别把LCT的结构当成真实的树的结构。
题目链接:https://vjudge.net/problem/HDU-5398
就是要快速求两点间路径上距离最短的边。
比如求u和v。
那就先mroot(u),使u成为根。
然后再access(v),打通u,v之间的路径,使得u和v在同一棵Auxiliary Tree中。此时u是第一个值,v是最后一个值。这棵Auxiliary Tree包含且仅包含u到v路径上的所有节点。
然后Splay(v),使得v伸展到这棵Auxiliary Tree的根。因为v是最后一个节点,所以此时v没有右儿子。
如果我们知道一个节点所在子树(对于其所在的Auxiliary Tree而言)所代表的路径上的最短边以及对应的节点编号,
那么上述问题就可以直接解决了。
所以我们要维护一个节点所在子树所代表的路径上的最短边以及对应的节点编号。
具体而言就是要维护以下值
1、节点所在子树所代表的路径上的最短边长。
2、最短变长所对应的两个端点。
3、节点所在子树所代表的路径的头和尾。(具体就是中序遍历第一个访问和最后一个访问的节点)
1和2是我们需要的值。
3可以帮助我们从儿子转移到父亲。
关于数论方面的优化
对于一个数x,我们只需要枚举它的质因数y,然后考虑z=x/y。尝试将x与z连边。一定最优。
因为如果y不是质因数,比如y=a*b,那么z=x/y=x/(a*b)=(x/a)/b。
由于我们是从小到大加点,所以之前已经考虑过(x/a)这个数了,对于(x/a)这个数当然也已经考虑过和z=(x/a)/b连边了,因此不用再重复考虑。
1<=n<=1e5,质因数的个数不超过10个。所以总的时间复杂度为O(10nlogn)。
Eratosthenes筛法用于筛出质数。稍加改造就可以筛出质因数或因数。时间复杂度都为O(nlogn)。
代码
#include<stdio.h>#include<algorithm>#include<vector>#include<math.h>//#include<windows.h>using namespace std;typedef long long ll;const int maxn = 100010;const int inf = 0x3f3f3f3f;struct node{ int val; int fa,ch[2]; bool reverse,is_root; int MIN; int u,v; int pp[2]; void init(int x) { val=x; fa=ch[0]=ch[1]=0; reverse=0; is_root=1; MIN=inf; u=v=-1; pp[0]=pp[1]=x; }}T[maxn];int gcd(int a,int b){ return !b?a:gcd(b,a%b);}void pushreverse(int x){ if(!x) return; swap(T[x].ch[0],T[x].ch[1]); swap(T[x].pp[0],T[x].pp[1]); T[x].reverse^=1;}void pushdown(int x){ if(T[x].reverse) { pushreverse(T[x].ch[0]); pushreverse(T[x].ch[1]); T[x].reverse=false; }}void pushup(int x){ T[x].MIN=inf; T[x].u=T[x].v=-1; T[x].pp[0]=T[x].pp[1]=x; pushdown(x); for(int i=0;i<2;i++) { if(T[x].ch[i]) { T[x].pp[i]=T[T[x].ch[i]].pp[i]; if(T[x].MIN>T[T[x].ch[i]].MIN) { T[x].MIN=T[T[x].ch[i]].MIN; T[x].u=T[T[x].ch[i]].u; T[x].v=T[T[x].ch[i]].v; } int GCD=gcd(T[x].val,T[T[x].ch[i]].pp[i^1]); if(T[x].MIN>GCD) { T[x].MIN=GCD; T[x].u=x; T[x].v=T[T[x].ch[i]].pp[i^1]; } } }}int getson(int x){ return x==T[T[x].fa].ch[1];}void rotate(int x){ if(T[x].is_root) return; int k=getson(x); int fa=T[x].fa; int fafa=T[fa].fa; pushdown(fa); pushdown(x); T[fa].ch[k]=T[x].ch[k^1]; if(T[x].ch[k^1]) T[T[x].ch[k^1]].fa=fa; T[x].ch[k^1]=fa; T[fa].fa=x; T[x].fa=fafa; if(T[fa].is_root) { T[fa].is_root=false; T[x].is_root=true; } else { T[fafa].ch[fa==T[fafa].ch[1]]=x; } pushup(fa); pushup(x);}void push(int x){ if(!T[x].is_root) push(T[x].fa); pushdown(x);}void Splay(int x){ push(x); for(int fa;!T[x].is_root;rotate(x)) { if(!T[fa=T[x].fa].is_root) { rotate((getson(x)==getson(fa))?fa:x); } }}void access(int x){ int y=0; do { Splay(x); T[T[x].ch[1]].is_root=true; T[T[x].ch[1]=y].is_root=false; pushup(x); x=T[y=x].fa; }while(x);}void mroot(int x){ access(x); Splay(x); pushreverse(x);}void link(int u,int v){ mroot(u); T[u].fa=v;}void cut(int u,int v){ mroot(u); access(v); Splay(v); pushdown(v); T[T[v].ch[0]].fa=T[v].fa; T[T[v].ch[0]].is_root=true; T[v].fa=0;T[v].ch[0]=0; pushup(v);}vector<int>vec[maxn];int vis[maxn];ll a[maxn];ll ans;void getpri(){ for(int i=2;i<maxn;i++) if(!vis[i]) for(int j=i;j<maxn;j+=i) { vis[j]=1; vec[j].push_back(i); }}void debug(){ puts("----------"); for(int i=1;i<=21;i++) { printf("i:%d fa:%d le:%d ri:%d rt:%d rev:%d lll:%d rrr:%d\n",i,T[i].fa,T[i].ch[0],T[i].ch[1],T[i].is_root,T[i].reverse,T[i].pp[0],T[i].pp[1]); } puts("----------");}void init(){ getpri(); ans=0; a[0]=0; a[1]=0; T[1].init(1); for(int i=2;i<maxn;i++) { T[i].init(i); bool f=1; for(int j=0;j<(int)vec[i].size();j++) { int x = vec[i][j]; x=i/x; if(f) { link(x,i); ans+=x; f=false; //debug(); } else { mroot(i); access(x); Splay(x); //debug(); int MIN = T[T[x].ch[0]].MIN; int u = T[T[x].ch[0]].u; int v = T[T[x].ch[0]].v; int GCD = T[x].MIN; if(MIN>GCD) { MIN=GCD; u=x; v=T[x].ch[0]; } if(MIN<x) { cut(u,v); link(x,i); ans-=MIN; ans+=x; } } } a[i]=ans; }}int n;void solve(){ printf("%lld\n",a[n]);}int main(){ //double s = GetTickCount(); init(); //double e = GetTickCount(); //printf("%lf\n",e-s); //freopen("5.txt","w",stdout); //for(int i=1;i<maxn;i++) // printf("%d:%lld\n",i,a[i]); while(~scanf("%d",&n)) solve(); return 0;}
- LCT(GCD Tree,HDU 5398)
- hdu 5398:GCD Tree lct
- HDU 5398 GCD TREE LCT维护贪心
- [LCT 动态最大生成树] HDU 5398 GCD Tree
- hdu 5398 GCD Tree 2015多校联合训练赛#9 LCT,动态生成树
- HDU 5398 GCD Tree
- hdu 5398 GCD Tree
- hdu 5002 Tree (LCT)
- hdu 5002 Tree (LCT)
- [GCD最小生成树 LCT] HDU5398 .GCD TREE
- [BZOJ3282]Tree(LCT)
- [BZOJ2631]tree(LCT)
- hdu5002:Tree (LCT)
- BZOJ2631:tree(LCT)
- [BZOJ2631]tree(LCT)
- 【LCT维护最大生成树】[HDU5389]GCD Tree
- hdu 5052 (LCT)
- 【HDU】4010 Query on The Trees 动态树之Link Cut Tree(LCT)
- 几种加密方式
- ACMer Training 学习指导
- 洛谷 P1799 数列
- RH124-第二节-linux中的基本命令
- [转载]Android系统的运行机制: 启动流程与层间交互
- LCT(GCD Tree,HDU 5398)
- 容器中安装ssh,可以ssh到别的机器,但是别的机器ssh不上该容器
- oracle11g_64位连接32位PLSQL_Developer配置
- java反射
- 从Fragment嵌套fragment到Viewpager嵌套Fragment再嵌套fragment
- Codeforces-713C-Sonya and Problem Wihtout a Legend
- liunx基础命令 一、系统管理与设置
- 东软JavaWeb实训记-DAY4-Servlet+frame框架页面的实现+不带框架的完整项目结构
- 10-Vue指令之V-bind