【LOJ】#2722. 「NOI2018」情报中心

https://loj.ac/problem/2722

题解

考场上想了60分,但是由于自己不知道在怎么zz,我连那个ai<bi都没看到,误以为出题人没给lca不相同的部分分,然后觉得lca不同的部分想出来了要是相出lca相同的不就肝过去了……最后剩下的想法就是……为啥没给lca不同的呢……是我想错了???
剩了一个小时写暴力好像当时已经精神失常了,算了不想说了

出了考场写了一下60分,细节真是多到让我吐了,我代码能力疯狂下降吗,写了60分就370行了 出题人大毒瘤啊

从头到尾说一下部分分

前20给枚举链求链交的\(n^2\)暴力

再15分,似乎可以线段树,但是我归到S1的部分了

再15分c=0,可以枚举一个公共lca,求两个最小的v值,可以线段树合并,在lca处删除

再15分,就是相交部分是一条链的,这个枚举树上的每个点作为公共lca,然后我们就发现是
两条链的价值-代价 - 链交部分的价值
而链交部分的价值,就是这这个点深度 - 两条链中较低点lca的深度
忽略到枚举的点是常数
就是val1 - dis[lca1] + val2 或者 val2 - dis[lca2] + val1中的最大值即可,如果选了深度较小lca会被更新
直接线段树合并维护就好

猫锟卡乱搞了,大家散了吧

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <queue>
#include <ctime>
#include <map>
#include <set>
#define fi first
#define se second
#define pii pair<int,int>
//#define ivorysi
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define MAXN 50005
using namespace std;
typedef long long int64;
typedef double db;
typedef unsigned int u32;
template<class T>
void read(T &res) {
    res = 0;T f = 1;char c = getchar();
    while(c < '0' || c > '9') {
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9' ) {
        res = res * 10 - '0' + c;
        c = getchar();
    }
    res *= f;
}
template<class T>
void out(T x) {
    if(x < 0) {x = -x;putchar('-');}
    if(x >= 10) {
        out(x / 10);
    }
    putchar('0' + x % 10);
}
struct node {
    int to,next;int64 val;
}E[MAXN * 2];
struct qry_node {
    int u,v,lca;int64 val;
}qry[MAXN * 2];
int M,N,sumE,head[MAXN],fa[MAXN],dep[MAXN],pos[MAXN],st[MAXN * 2][20],idx,len[MAXN * 2],cnt;
int64 dis[MAXN],ans;
bool all_zero,all_lca_1,all_lca_distinct;
bool has[MAXN];
void add(int u,int v,int64 c) {
    E[++sumE].to = v;
    E[sumE].next = head[u];
    E[sumE].val = c;
    head[u] = sumE;
}
int min_dep(int a,int b) {
    return dep[a] < dep[b] ? a : b;
}
int max_dep(int a,int b) {
    return dep[a] > dep[b] ? a : b;
}
int lca(int a,int b) {
    a = pos[a];b = pos[b];
    if(a > b) swap(a,b);
    int l = len[b - a + 1];
    return min_dep(st[a][l],st[b - (1 << l) + 1][l]);
}
int64 Dist(int a,int b) {
    return dis[a] + dis[b] - 2 * dis[lca(a,b)];
}
void dfs(int u) {
    dep[u] = dep[fa[u]] + 1;
    st[++idx][0] = u;
    pos[u] = idx;
    for(int i = head[u] ;i ; i = E[i].next) {
        int v = E[i].to;
        if(v != fa[u]) {
            fa[v] = u;
            dis[v] = dis[u] + E[i].val;
            dfs(v);
            st[++idx][0] = u;
        }
    }
}
void Init() {
    sumE = 0;idx = 0;ans = -1e18;
    all_zero = 1;all_lca_1 = 1;all_lca_distinct = 1;
    memset(has,0,sizeof(has));
    for(int i = 1 ; i <= N ; ++i) head[i] = 0;
    read(N);
    int a,b;int64 c;
    for(int i = 1 ; i < N ; ++i) {
        read(a);read(b);read(c);
        add(a,b,c);add(b,a,c);
        if(c != 0) all_zero = 0;
    }
    dfs(1);
    for(int j = 1 ; j <= 19 ; ++j) {
        for(int i = 1 ; i <= idx ; ++i) {
            if(i + (1 << j) - 1 > idx) break;
            st[i][j] = min_dep(st[i][j - 1],st[i + (1 << j - 1)][j - 1]);
        }
    }
    read(M);
    for(int i = 1 ; i <= M ; ++i) {
        read(a);read(b);read(c);
        qry[i].u = a;qry[i].v = b;qry[i].lca = lca(a,b);
        qry[i].val = Dist(a,b) - c;
        if(has[qry[i].lca]) all_lca_distinct = 0;
        if(qry[i].lca != 1) all_lca_1 = 0;
        has[qry[i].lca] = 1;
    }
}
namespace task1 {
    void Solve() {
        for(int i = 1 ; i <= M ; ++i) {
            for(int j = 1 ; j <= M ; ++j) {
                if(i == j) continue;
                if(dep[qry[i].lca] < dep[qry[j].lca]) continue;
                int u = max_dep(qry[i].lca,lca(qry[i].u,qry[j].u));
                int v = max_dep(qry[i].lca,lca(qry[i].v,qry[j].v));
                if(u == v) {
                    u = max_dep(qry[i].lca,lca(qry[i].u,qry[j].v));
                    v = max_dep(qry[i].lca,lca(qry[i].v,qry[j].u));
                }
                if(u != v) {
                    ans = max(ans,qry[i].val + qry[j].val - Dist(u,v));
                }
            }
        }

    }
    int check() {
        for(int i = 1 ; i <= M ; ++i) {
            for(int j = 1 ; j <= M ; ++j) {
                if(i == j) continue;
                if(dep[qry[i].lca] < dep[qry[j].lca]) continue;
                int u = max_dep(qry[i].lca,lca(qry[i].u,qry[j].u));
                int v = max_dep(qry[i].lca,lca(qry[i].v,qry[j].v));
                if(u == v) {
                    u = max_dep(qry[i].lca,lca(qry[i].u,qry[j].v));
                    v = max_dep(qry[i].lca,lca(qry[i].v,qry[j].u));
                }
                if(u != v) {
                    if(ans == qry[i].val + qry[j].val - Dist(u,v)) {
                        out(i);space;out(j);enter;
                    }
                }
            }
        }
    }
};
namespace task2 {
    struct tr_node {
        int lc,rc;
        int64 maxa,maxb;
    }tr[MAXN * 40];
    int Ncnt,rt[MAXN];
    vector<int> st[MAXN],ed[MAXN];
    bool cmp(qry_node a,qry_node b) {
        return a.v < b.v;
    }
    void update(int u) {
        int64 la,lb,ra,rb;
        la = lb = ra = rb = -2e18;
        if(tr[u].lc) {
            la = tr[tr[u].lc].maxa;lb = tr[tr[u].lc].maxb;
        }
        if(tr[u].rc) {
            ra = tr[tr[u].rc].maxa;rb = tr[tr[u].rc].maxb;
        }
        tr[u].maxa = max(la,ra);
        tr[u].maxb = max(lb,rb);
    }
    int Merge(int u,int v,int64 val) {
        if(!u) return v;
        if(!v) return u;
        pii t[2] = {mp(tr[u].lc,tr[v].rc),mp(tr[u].rc,tr[v].lc)};
        for(int i = 0 ; i <= 1 ; ++i) {
            int a = t[i].fi,b = t[i].se;
            if(!a || !b) continue;
            ans = max(tr[a].maxa + tr[b].maxb + val,ans);
            ans = max(tr[a].maxb + tr[b].maxa + val,ans);
        }
        tr[u].lc = Merge(tr[u].lc,tr[v].lc,val);
        tr[u].rc = Merge(tr[u].rc,tr[v].rc,val);
        
        if(!tr[u].lc && !tr[u].rc) {
            tr[u].maxa = max(tr[u].maxa,tr[v].maxa);
            tr[u].maxb = max(tr[u].maxb,tr[v].maxb);
        }
        else update(u);
        return u;
    }
    void Insert(int &u,int L,int R,int pos,int64 va,int64 vb,bool on,int64 val) {
        if(!u) {
            u = ++Ncnt;
            tr[u].lc = tr[u].rc = 0;
            tr[u].maxa = tr[u].maxb = -2e18;
        }
        if(L == R) {
            if(on) {
                tr[u].maxa = va;tr[u].maxb = vb;
            }
            else {
                tr[u].maxa = max(tr[u].maxa,va);
                tr[u].maxb = max(tr[u].maxb,vb);
            }
            return;
        }
        int mid = (L + R) >> 1;
        if(pos <= mid) {
            Insert(tr[u].lc,L,mid,pos,va,vb,on,val);
            if(tr[u].rc) {
                ans = max(va + tr[tr[u].rc].maxb + val,ans);
                ans = max(vb + tr[tr[u].rc].maxa + val,ans);
            }
        }
        else {
            Insert(tr[u].rc,mid + 1,R,pos,va,vb,on,val);
            if(tr[u].lc) {
                ans = max(va + tr[tr[u].lc].maxb + val,ans);
                ans = max(vb + tr[tr[u].lc].maxa + val,ans);
            }
        }

        update(u);
    }
    void dfs(int u) {
        int s = st[u].size();
        int64 ma,mb;
        for(int i = 0 ; i < s ; ++i) {
            int id = st[u][i];
            if(dep[qry[id].lca] < dep[u]) {
                Insert(rt[u],1,N,dep[qry[id].lca],qry[id].val,qry[id].val + dis[qry[id].lca],0,-dis[u]);
            }
        }
        int64 tmp = -1e18;
        for(int i = head[u] ; i ; i = E[i].next) {
            int v = E[i].to;
            if(v != fa[u]) {
                dfs(v);
                if(rt[v]) Insert(rt[v],1,N,dep[u],-2e18,-2e18,1,-dis[u]);
                rt[u] = Merge(rt[u],rt[v],-dis[u]);
            }
        }
        ans = max(ans,tmp);
        if(dep[N] == N) {
            int s = ed[u].size();
            int64 v = 2e18;
            for(int i = 0 ; i < s ; ++i) {
                int id = ed[u][i];
                if(qry[id].u == qry[id].v) continue;
                ans = max(ans,qry[id].val - v);
                int64 t = -qry[id].val + 2 * (dis[qry[id].v] - dis[qry[id].u]);
                v = min(v,t);
            }
        }
    }
    void Solve() {
        Ncnt = 0;
        for(int i = 1 ; i <= N ; ++i) {
            rt[i] = 0;st[i].clear();ed[i].clear();
        }
        for(int i = 1 ; i <= M ; ++i) {
            if(qry[i].u > qry[i].v) swap(qry[i].u,qry[i].v);
        }
        sort(qry + 1,qry + M + 1,cmp);
        for(int i = 1 ; i <= M ; ++i) {
            st[qry[i].u].pb(i);
            st[qry[i].v].pb(i);
            ed[qry[i].lca].pb(i);
        }
        dfs(1);
    }
};
namespace task3 {
    vector<int> st[MAXN],ed[MAXN];
    struct tr_node {
        int lc,rc;
        int64 v,s;
    }tr[MAXN * 40];
    int rt[MAXN],Ncnt;
    void update(int u) {
        int64 lv,rv;
        lv = rv = -2e18;tr[u].s = -1e18;
        if(tr[u].lc) {lv = tr[tr[u].lc].v;tr[u].s = max(tr[u].s,tr[tr[u].lc].s);}
        if(tr[u].rc) {rv = tr[tr[u].rc].v;tr[u].s = max(tr[u].s,tr[tr[u].rc].s);}
        tr[u].v = max(lv,rv);
        tr[u].s = max(tr[u].s,lv + rv);
    }
    int Merge(int u,int v) {
        if(!u) return v;
        if(!v) return u;
        tr[u].lc = Merge(tr[u].lc,tr[v].lc);
        tr[u].rc = Merge(tr[u].rc,tr[v].rc);
        if(tr[u].lc || tr[u].rc) update(u);
        return u;
    }
    void Insert(int &u,int L,int R,int pos,int64 v) {
        if(!u) {
            u = ++Ncnt;
            tr[u].lc = tr[u].rc = 0;tr[u].v = -2e18;
            tr[u].s = -1e18;
        }
        if(L == R) {
            tr[u].v = v;return;
        }
        int mid = (L + R) >> 1;
        if(pos <= mid) Insert(tr[u].lc,L,mid,pos,v);
        else Insert(tr[u].rc,mid + 1,R,pos,v);
        update(u);
    }
    void dfs(int u) {
        for(int i = head[u] ; i ; i = E[i].next) {
            int v = E[i].to;
            if(v != fa[u]) {
                dfs(v);
                rt[u] = Merge(rt[u],rt[v]);
            }
        }
        int s = st[u].size();
        for(int i = 0 ; i < s ; ++i) {
            int id = st[u][i];
            if(dep[qry[id].lca] < dep[u]) {
                Insert(rt[u],1,M,id,qry[id].val);
            }
        }
        s = ed[u].size();
        for(int i = 0 ; i < s ; ++i) {
            int id = ed[u][i];
            Insert(rt[u],1,M,id,-2e18);
        }
        if(rt[u]) {
            ans = max(ans,tr[rt[u]].s);
        }
        
    }
    void Solve() {
        Ncnt = 0;
        for(int i = 1 ; i <= N ; ++i) {
            st[i].clear();ed[i].clear();rt[i] = 0;
        }
        for(int i = 1 ; i <= M ; ++i) {
            st[qry[i].u].pb(i);
            st[qry[i].v].pb(i);
            ed[qry[i].lca].pb(i);
        }
        dfs(1);
    }
};
namespace task4 {
    vector<int> st[MAXN];
    pii C[MAXN];
    int64 V[MAXN * 4];
    int f[MAXN * 4],cnt;
    int64 get_dist(int a,int b) {
        return Dist(f[a],f[b]) + V[a] + V[b];
    }
    void Merge(pii &path,int p) {
        if(!p) return;
        if(!path.se) path.se = p;
        else if(!path.fi) path.fi = p;
        else {
            int64 x1 = get_dist(p,path.fi),x2 = get_dist(p,path.se),x3 = get_dist(path.fi,path.se);
            if(x1 >= max(x2,x3)) {
                path = mp(p,path.fi);
            }
            else if(x2 > max(x1,x3)) {
                path = mp(p,path.se);
            }
        }
    }
    void dfs(int u) {
        int s = st[u].size();
        C[u] = mp(0,0);
        if(u != 1) {
            for(int i = 0 ; i < s ; ++i) {
                Merge(C[u],st[u][i]);
                if(C[u].fi && C[u].se) {
                    ans = max(ans,get_dist(C[u].fi,C[u].se) / 2 - dis[u]);
                }
            }
        }
        for(int i = head[u] ; i ; i = E[i].next) {
            int v = E[i].to;
            if(v != fa[u]) {
                dfs(v);
                int t1[2] = {C[u].fi,C[u].se};
                int t2[2] = {C[v].fi,C[v].se};
                if(u != 1) {
                    for(int j = 0 ; j <= 1 ; ++j) {
                        for(int k = 0 ; k <= 1 ; ++k) {
                            int s = t1[j],t = t2[k];
                            if(!s || !t) continue;
                            ans = max(ans,get_dist(s,t) / 2 - dis[u]);
                        }
                    }
                }
                Merge(C[u],C[v].fi);Merge(C[u],C[v].se);
            }
        }
    }
    void Solve() {
        for(int i = 1 ; i <= N ; ++i) {
            st[i].clear();  
        }
        cnt = 0;
        for(int i = 1 ; i <= M ; ++i) {
            qry[i].val = -qry[i].val + Dist(qry[i].u,qry[i].v);
            V[++cnt] = Dist(qry[i].u,qry[i].v) - 2 * qry[i].val + dis[qry[i].u];
            f[cnt] = qry[i].v;
            st[qry[i].u].pb(cnt);
            V[++cnt] = Dist(qry[i].u,qry[i].v) - 2 * qry[i].val + dis[qry[i].v];
            f[cnt] = qry[i].u;
            st[qry[i].v].pb(cnt);
        }
        dfs(1);
    }
};
namespace task5 {
    vector<pii > st[MAXN];
    map<int,pii > dp[MAXN];
    int64 V[MAXN * 4];
    int f[MAXN * 4],cnt;
    int64 get_dist(int a,int b) {
        return Dist(f[a],f[b]) + V[a] + V[b];
    }
    void Merge(pii &path,int p) {
        if(!p) return;
        if(!path.se) path.se = p;
        else if(!path.fi) path.fi = p;
        else {
            int64 x1 = get_dist(p,path.fi),x2 = get_dist(p,path.se),x3 = get_dist(path.fi,path.se);
            if(x1 >= max(x2,x3)) {
                path = mp(p,path.fi);
            }
            else if(x2 > max(x1,x3)) {
                path = mp(p,path.se);
            }
        }
    }
    void dfs(int u) {
        int s = st[u].size();
        for(int i = 0 ; i < s ; ++i) {
            pii t = st[u][i];
            if(!dp[u].count(t.se)) {
                dp[u][t.se] = mp(0,0);
            }
            Merge(dp[u][t.se],t.fi);
            if(dp[u][t.se].fi && dp[u][t.se].se) {

                ans = max(ans,get_dist(dp[u][t.se].fi,dp[u][t.se].se) / 2 - dis[u] + dis[t.se]);
            }
        }
        for(int i = head[u] ; i ; i = E[i].next) {
            int v = E[i].to;
            if(v != fa[u]) {
                dfs(v);
                if(dp[v].size() > dp[u].size()) swap(dp[u],dp[v]);
                map<int,pii >::iterator it = dp[v].begin();
                while(it != dp[v].end()) {
                    if(u != it->fi && dp[u].count(it->fi)) {
                        int t1[2] = {dp[u][it->fi].fi,dp[u][it->fi].se};
                        int t2[2] = {dp[v][it->fi].fi,dp[v][it->fi].se};
                        for(int j = 0 ; j <= 1 ; ++j) {
                            for(int k = 0 ; k <= 1 ; ++k) {
                                int s = t1[j],t = t2[k];
                                if(!s || !t) continue;
                                ans = max(ans,get_dist(s,t) / 2 - dis[u] + dis[it->fi]);
    
                            }
                        }
                        Merge(dp[u][it->fi],it->se.fi);
                        Merge(dp[u][it->fi],it->se.se);
                    }
                    else {
                        dp[u][it->fi] = it->se;
                    }
                    ++it;
                }
                dp[v].clear();
            }
        }
        dp[u].erase(u);
    }
    void Solve() {
        cnt = 0;
        for(int i = 1 ; i <= N ; ++i) {
            st[i].clear();dp[i].clear();
        }
        for(int i = 1 ; i <= M ; ++i) {
            qry[i].val = -qry[i].val + Dist(qry[i].u,qry[i].v);
            V[++cnt] = Dist(qry[i].u,qry[i].v) - 2 * qry[i].val + dis[qry[i].u] - dis[qry[i].lca];
            f[cnt] = qry[i].v;
            if(qry[i].u != qry[i].lca) st[qry[i].u].pb(mp(cnt,qry[i].lca));
            V[++cnt] = Dist(qry[i].u,qry[i].v) - 2 * qry[i].val + dis[qry[i].v] - dis[qry[i].lca];
            f[cnt] = qry[i].u;
            if(qry[i].v != qry[i].lca) st[qry[i].v].pb(mp(cnt,qry[i].lca));
        }
        dfs(1);
    }
};
int main() {
#ifdef ivorysi
    freopen("center4.in","r",stdin);
#else
    freopen("center.in","r",stdin);
    freopen("center.out","w",stdout);
#endif
    for(int i = 2 ; i <= 100000 ; ++i) len[i] = len[i / 2] + 1;
    int T;
    read(T);
    cnt = 0;
    while(T--) {
        Init();
        if(M <= 300) task1::Solve();
        else if(all_lca_1) task4::Solve();
        else if(dep[N] == N) task2::Solve();
        else if(all_zero) task3::Solve();
        else if(all_lca_distinct) task2::Solve();
        else {
            task2::Solve();
            task5::Solve();
        }
        
        if(ans <= -1e18) puts("F");
        else {out(ans);enter;}
    }
    return 0;
}

直接调用task2和task5可以通过,然鹅我分部分分写的话直接用……task2处理一条链上同时所有lca为1的路径似乎有问题?懒得debug了= =
12.8K写得我真的非常开心

再20分的话,就非常神仙了
有个性质是链并的两倍等于两条链长 + u1 u2距离 + v1 v2距离
这时候再沿用前面思路的话就非常鸽
我们拆个式子
枚举u1和u2的lca是r
然后答案就是
dis[u_1] + dis[u_2] - 2 * dis[r] + (1链长价值 - 代价) - (2链长价值 - 代价) + dist(v1,v2)
我们多个附加点p1连向v1,边权是链长价值-代价 + dis[u_1]
当遇到u_1 的时候,加进去p_1,就相当于对于一个形态固定的树,加进去一个点可使用,找两个点集中各一个点的一条最长链
因为只有增加操作,那么两个点集中的各一个端点必然是两个点集中各自最长链的端点

最后20分,只要做一遍S1,再记录一下lca做一下S2,数组启发式合并就行……

我代码写的好长

NOI考完,我想我知道
我大概是LN的绝望了

转载于:https://www.cnblogs.com/ivorysi/p/9392286.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值