计蒜客 青云的机房组网方案

来源:互联网 发布:炫光制作软件 编辑:程序博客网 时间:2024/04/30 07:16

题面:

有一棵点数105的树,每个节点有一个权值,权值范围是[1,105]的,问所有两个权值互质的节点之间距离的和

题解


关于虚树,记下一些key point以后要是忘了可以回来看看

虚树是保留原树的所选定的一些节点,保留这些选定节点两两的LCA,按照这些保留点在原树中的关系所建的一个新树。

可以保证如果选定节点是k个,那么虚树的节点不会超过2×k。考虑每次拿走最深的两个相邻节点并且加入这两个节点的LCA,这个结论应该是显然的。

建立虚树的方法是将选定节点按照dfs序排序之后,维护一个深度单调的栈,栈中保存的是可能和下一个节点产生父子关系的点。这些点满足在同一条路径上。

每次加入一个点的时候,将这个点和栈顶的点(如果栈空的话将这个点直接入栈就可以了)的lca计算出来,找到lca在栈中维护的路径的链的位置去更新栈。具体见代码。


得到虚树之后每个边的贡献就是这个边两遍的点的个数的乘积,累加就好了。

#include<bits/stdc++.h>using namespace std;#define LL long longconst int maxn = 212345,maxm = 212345,max_log = 18;const int ROOT = 1;vector<pair<int,LL> > vedge[maxn];vector<int> edge[maxn];LL siz[maxn];int is[maxn];void dffs(int st,int fa){    siz[st] = is[st];    for(auto x : vedge[st]){        if(x.first != fa){            dffs(x.first,st);            siz[st] += siz[x.first];        }    }}LL dfss(int st,int fa,int n){    LL ret = 0;    for(auto it : vedge[st]){        int x = it.first; LL v = it.second;        if(x != fa){            ret += dfss(x,st,n);            ret += v * siz[x] * (n-siz[x]);        }    }    return ret;}LL dpfs(int n){    dffs(0,-1);    return dfss(0,-1,siz[0]);}int dfn[maxn],_cnt;int deep[maxn],fa[maxn][max_log];void dfs(int st,int Fa,int Deep=1){    dfn[st] = _cnt++;    for(int i=1;i<max_log;i++)        fa[st][i] = -1;    fa[st][0] = Fa,deep[st] = Deep;    for(auto x : edge[st]){        if(x == Fa) continue;        dfs(x,st,Deep+1);    }}void init(int n){    _cnt = 1;    memset(fa,-1,sizeof(fa));    dfs(ROOT,-1);    for (int j = 1;j < max_log;j++){        for (int i = 1;i <= n;i++){            if (fa[i][j-1] != -1){                fa[i][j] = fa[fa[i][j-1]][j-1];            }        }    }}int Lca(int x,int y){    LL ix,iy;    ix = iy = 0;    if (deep[x] < deep[y]) swap(x,y);    for (int i = max_log-1;i >= 0;i--){        if (deep[fa[x][i]] >= deep[y]){            x = fa[x][i];        }    }    if (x == y) return x;     for (int i = max_log-1;i >= 0;i--){        if (fa[x][i] != fa[y][i]){            x = fa[x][i];            y = fa[y][i];        }    }    return fa[x][0];}int val[maxn],cid[maxn],sid[maxn];int cnt;int tcid(int v){    if(sid[v] != -1) return sid[v];    sid[v] = cnt, cid[cnt] = v;    return cnt++;}void Link(int st,int ed,int v = -1){    if(v == -1) v = abs(deep[st] - deep[ed]);    if(v==0) return;    st = tcid(st),ed = tcid(ed);    vedge[st].push_back(make_pair(ed,v));    vedge[ed].push_back(make_pair(st,v));}struct Stack{    int sta[maxn],_cnt;    int last;    void init(){ _cnt = 0, last = -1; }    bool empty(){ return _cnt==0; }    int top(){ return sta[_cnt-1]; }    void push(int x){        if(last != -1)             Link(last,x);        sta[_cnt++] = x;        last = -1;    }    void pop(){        if(last != -1)            Link(this->top(),last);        last = this->top();        _cnt--;    } }S;vector<int> hav[maxn];LL bvtree(int k){    sort(hav[k].begin(),hav[k].end(),[](int x,int y){return dfn[x] < dfn[y];});    cnt = 0;    S.init();    for(auto x : hav[k]){        if(S.empty()){             S.push(x);            continue;        }        int lca = Lca(S.top(),x);        while(S.empty()==false && deep[S.top()] >= deep[lca])            S.pop();        if(S.empty() || deep[S.top()] < deep[lca])            S.push(lca);        if(lca != x)            S.push(x);    }    while(S.empty()==false) S.pop();    for(int i=0;i<cnt;i++)        is[i] = val[cid[i]] % k == 0;    LL ret = dpfs(cnt);    for(int i=0;i<cnt;i++){        vedge[i].clear();        sid[cid[i]] = -1;        cid[i] = -1;    }    return ret;}vector<int> fac[maxn];int mu[maxn];int main(){    int n;    for(int i=1;i<maxn;i++){        for(int j=i;j<maxn;j+=i)            fac[j].push_back(i);    }    memset(mu,0,sizeof(mu));    mu[1] = 1;    for(int i=1;i<maxn;i++){        for(int j=2*i;j<maxn;j+=i)            mu[j] -= mu[i];    }    while(~scanf("%d",&n)){        for(int i=0;i<=n;i++)            edge[i].clear(),hav[i].clear(),vedge[i].clear();        int v;        for(int i=1;i<=n;i++){            scanf("%d",&v);            val[i] = v;            for(auto x : fac[v]){                if(mu[x]) hav[x].push_back(i);            }        }        int l,r;        for(int i=1;i<n;i++){            scanf("%d %d",&l,&r);            edge[l].push_back(r);            edge[r].push_back(l);        }        init(n);        memset(sid,-1,sizeof(sid));        LL ans = 0;        for(int i=1;i<maxn;i++){            if(hav[i].empty() == false)                ans += mu[i] * bvtree(i);        }        printf("%lld\n",ans);    }    return 0;}

附上一个比赛时的弱鸡代码

#include<bits/stdc++.h>using namespace std;const int maxn = 112345,max_log = 18;vector<int> edge[maxn];vector<pair<int,int> >vedge[maxn];int dis[maxn];void pdfs(int st,int fa){    for(auto it : vedge[st]){        if(it.first == fa) continue;        dis[it.first] = dis[st] + it.second;        pdfs(it.first,st);    }}pair<int,int> getPair(int n,int st){    dis[st] = 0;    pdfs(st,-1);    st = max_element(dis,dis+n) - dis;    dis[st] = 0;    pdfs(st,-1);    return make_pair(st,max_element(dis,dis+n) - dis);}//Need checkconst int ROOT = 1;int deep[maxn],dfn[maxn],fa[maxn][max_log];int _cnt;void dfs(int st,int Fa,int Deep=1){    for(int i=1;i<max_log;i++)        fa[st][i] = -1;    dfn[st] = _cnt++;    fa[st][0] = Fa,deep[st] = Deep;    for(auto x : edge[st]){        if(x == Fa) continue;        dfs(x,st,Deep+1);    }}void init(int n){    memset(fa,-1,sizeof(fa));    _cnt = 1;    dfs(ROOT,-1);    for (int j = 1;j < max_log;j++){        for (int i = 1;i <= n;i++){            if (fa[i][j-1] != -1){                fa[i][j] = fa[fa[i][j-1]][j-1];            }        }    }}int Lca(int x,int y){    if (deep[x] < deep[y]) swap(x,y);    for (int i = max_log-1;i >= 0;i--){        if (deep[fa[x][i]] >= deep[y]){            x = fa[x][i];        }    }    if (x == y) return x;    for (int i = max_log-1;i >= 0;i--){        if (fa[x][i] != fa[y][i]){            x = fa[x][i];            y = fa[y][i];        }    }    return fa[x][0];}int cid[maxn],sid[maxn]; //assert sid is -1 initint vnt;int tcid(int v){    if(sid[v] != -1) return sid[v];    sid[v] = vnt, cid[vnt] = v;    return vnt++;}void Link(int st,int ed){    if(ed == -1 || st == ed) return;    int v = abs(deep[st]-deep[ed]);    st = tcid(st),ed = tcid(ed);    vedge[st].push_back(make_pair(ed,v));    vedge[ed].push_back(make_pair(st,v));}stack<int> S;vector<int> inp;pair<int,int> bvtree(){    if(inp.size() ==1) return make_pair(inp[0],inp[0]);    sort(inp.begin(),inp.end(),[](int x,int y){return dfn[x] < dfn[y];});    vnt = 0;    int last = -1;    while(S.empty()==false) S.pop();    for(auto x : inp){        if(S.empty()){            Link(x,last) ,last = -1 ,S.push(x) ;            continue;        }        int lca = Lca(S.top(),x);        while(!S.empty() && deep[S.top()] >= deep[lca])            Link(S.top(),last), last = S.top(), S.pop();        if(    S.empty() || deep[S.top()] <  deep[lca])            Link(lca    ,last), last = -1  ,S.push(lca);        if(lca != x) S.push(x) ;    }    while(!S.empty())        Link(S.top(),last), last = S.top(), S.pop();    auto ret = getPair(vnt,0);    ret.first = cid[ret.first] , ret.second = cid[ret.second];    for(int i=0;i<vnt;i++)        vedge[i].clear(), sid[cid[i]] = -1, cid[i] = -1;    return ret;}map<string,vector<int> >store;map<string,pair<int,int> >lis;int dist(int x,int y){    return deep[x] + deep[y] - deep[Lca(x,y)] * 2 + 1;}char name[10];int query(){    scanf("%s",name);    if(lis.find(name) == lis.end()){        scanf("%s",name);        return -1;    }    auto a = lis[name];    scanf("%s",name);    if(lis.find(name) == lis.end()){        return -1;    }    auto b = lis[name];    return max( max(dist(a.first,b.first) , dist(a.first,b.second)),                max(dist(a.second,b.first), dist(a.second,b.second)));}int main(){    int n,m;    while(~scanf("%d %d",&n,&m)){        store.clear(),lis.clear();        for(int i=1;i<=n;i++){            scanf("%s",name);            store[name].push_back(i);            edge[i].clear();        }        int l,r;        for(int i=1;i<n;i++){            scanf("%d %d",&l,&r);            edge[l].push_back(r);            edge[r].push_back(l);        }        init(n);        memset(sid,-1,sizeof(sid));        for(auto it : store){            inp = it.second;             lis[it.first] = bvtree();        }        while(m--){            printf("%d\n",query());        }    }    return 0;}
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 旋转眼线笔断了怎么办 眼睛去皮以后眉眼距窄怎么办 速写型总是画不准怎么办 速写人物不会打形怎么办 鼻头又圆又大怎么办 耳鸣嘴溃疡眼流泪上火怎么办 孩子看电视总挤眼睛怎么办 小孩老是咳嗽有痰怎么办 长时间看手机眼睛模糊怎么办 长时间看电脑眼睛模糊怎么办 手机玩多了眼睛模糊怎么办 手机看多了眼睛模糊怎么办 孩子玩手机眼睛红怎么办 手机玩多了眼睛红怎么办 手机看久了眼花怎么办 玩手机眼睛近视了怎么办 近视了怎么办30个字 吃了长牙的土豆怎么办 鸡蛋和土豆吃了怎么办 狗狗眼睛流血水怎么办 石粉粘土干了怎么办 樱花针管笔干了怎么办 想学linux不会c语言怎么办 被摩托车排气管烫伤了怎么办 泡泡糖粘在衣服上怎么办 皮卡书屋办卡怎么办 照证件照齐刘海怎么办 哈挺机床卡刀了怎么办 绝地求生卡在登陆页面怎么办 白鞋子长霉了怎么办 幸福树树干烂了怎么办 花椒树树叶掉落枝干发黑怎么办 茉莉枝干变干了怎么办 冲风了头蒙怎么办 不小心把腰扭了怎么办 白衣服发霉有小黑点怎么办 佛肚竹的枝叶都枯了怎么办 山竹一天吃多了怎么办 水养竹子叶子发黄怎么办 龙竹的竹杆黄了怎么办 散尾竹叶子发黑怎么办