UOJ400/LOJ2553 CTSC2018 暴力写挂 边分治、虚树

传送门——UOJ

传送门——LOJ


跟隔壁通道是一个类型的

要求的式子中有两个LCA,不是很方便,因为事实上在这种题目中LCA一般都是枚举的对象……

第二棵树上的LCA显然是动不了的,因为没有其他的量跟它有关了,于是考虑将\(dep_x+dep_y-dep_{LCA(x,y)}\)魔改一下

它等于\(\frac{1}{2} (dep_x+dep_y+dist_{x,y})\),LCA就没了

然后做法就很明晰了

在第一棵树上边分治,为了叙述方便称实点为原树上的点,虚点为边分治构建过程中加入的点

设边分治到边\((x,y)\),与\(x\)相连的连通块中的实点点集为\(L\),与\(y\)相连的连通块中的实点点集为\(R\)

那么当前边贡献的答案就是\(\max\limits_{i \in L} \max\limits_{j \in R} \frac{1}{2}(dist_i + dist_j + dep_i + dep_j + w(x,y)) - dep'_{LCA'(i,j)}\),其中\(dist_i\)表示\(i\)到边\((x,y)\)的距离

接着考虑枚举\(LCA'(i,j)\)。对\(L \cup R\)在第二棵树上建立虚树进行树形DP,设\(f_{i,0/1}\)表示第二棵子树上\(i\)的子树中且属于\(L/R\)的点集中\(dist + dep\)的最大值,在合并两棵子树的时候贡献答案即可。

为了方便可以将\(w(x,y)\)丢进\(L\)\(R\)的点权中

注意题目式子中\(x=y\)的情况

还有UOJ基数排序快LOJ快排快到底是个什么鬼

#include<bits/stdc++.h>
//This code is written by Itst
using namespace std;

inline int read(){
    int a = 0;
    char c = getchar();
    bool f = 0;
    while(!isdigit(c)){
        if(c == '-')
            f = 1;
        c = getchar();
    }
    while(isdigit(c)){
        a = (a << 3) + (a << 1) + (c ^ '0');
        c = getchar();
    }
    return f ? -a : a;
}

const int MAXN = 3.7e5 + 9;
int N , CCC;
long long val[MAXN] , ans;

namespace Tree2{
    struct Edge{
        int end , upEd , w;
    }Ed[MAXN << 1];
    int head[MAXN] , dep[MAXN] , fir[MAXN] , ST[21][MAXN << 1] , logg2[MAXN << 1];
    int cntEd , ts;
    long long len[MAXN];
    
    inline void addEd(int a , int b , int c){
        Ed[++cntEd].end = b;
        Ed[cntEd].upEd = head[a];
        head[a] = cntEd;
        Ed[cntEd].w = c;
    }
    
    void dfs(int x , int p){
        dep[x] = dep[p] + 1;
        ST[0][++ts] = x;
        fir[x] = ts;
        for(int i = head[x] ; i ; i = Ed[i].upEd)
            if(Ed[i].end != p){
                len[Ed[i].end] = len[x] + Ed[i].w;
                dfs(Ed[i].end , x);
                ST[0][++ts] = x;
            }
    }
    
    inline int cmp(int a , int b){
        return dep[a] < dep[b] ? a : b;
    }
    
    void init_ST(){
        for(int i = 2 ; i <= ts ; ++i)
            logg2[i] = logg2[i >> 1] + 1;
        for(int i = 1 ; 1 << i <= ts ; ++i)
            for(int j = 1 ; j + (1 << i) - 1 <= ts ; ++j)
                ST[i][j] = cmp(ST[i - 1][j] , ST[i - 1][j + (1 << (i - 1))]);
    }
    
    inline int LCA(int x , int y){
        x = fir[x];
        y = fir[y];
        if(x > y)
            swap(x , y);
        int t = logg2[y - x + 1];
        return cmp(ST[t][x] , ST[t][y - (1 << t) + 1]);
    }
    
    int st[MAXN] , top;
    long long dp[MAXN][2];
    vector < int > v , ch[MAXN];
    
    void init(){
        for(int i = 1 ; i < N ; ++i){
            int a = read() , b = read() , c = read();
            addEd(a , b , c);
            addEd(b , a , c);
        }
        dfs(1 , 0);
        init_ST();
        memset(dp , -0x3f , sizeof(dp));
        ans = dp[0][0];
    }
    
    void solve(int x){
        for(int i = 0 ; i < ch[x].size() ; ++i){
            solve(ch[x][i]);
            ans = max(ans , max(dp[x][0] + dp[ch[x][i]][1] , dp[x][1] + dp[ch[x][i]][0]) / 2 - len[x]);
            dp[x][0] = max(dp[x][0] , dp[ch[x][i]][0]);
            dp[x][1] = max(dp[x][1] , dp[ch[x][i]][1]);
            dp[ch[x][i]][0] = dp[ch[x][i]][1] = dp[0][0];
        }
        ch[x].clear();
    }
    
    bool cmp1(int a , int b){
        return fir[a] < fir[b];
    }
    
    int pot[11] , now[MAXN] , tmp[MAXN];
    void bSort(){
        int times = 1 , l = v.size();
        for(int i = 0 ; i < l ; ++i)
            now[i] = v[i];
        for(int i = 0 ; i <= 6 ; ++i){
            for(int j = 0 ; j <= 10 ; ++j)
                pot[j] = 0;
            for(int j = 0 ; j < l ; ++j)
                ++pot[(fir[now[j]] / times) % 10 + 1];
            for(int j = 1 ; j <= 10 ; ++j)
                pot[j] += pot[j - 1];
            for(int j = 0 ; j < l ; ++j)
                tmp[pot[(fir[now[j]] / times) % 10]++] = now[j];
            memcpy(now , tmp , sizeof(int) * l);
            times *= 10;
        } 
        v.clear();
        for(int i = 0 ; i < l ; ++i)
            v.push_back(now[i]);
    }
    
    void work(const vector < int >& nd1 , const vector < int >& nd2 , int c){
        ++CCC;
        for(int i = 0 ; i < nd1.size() ; ++i)
            dp[nd1[i]][0] = val[nd1[i]] + c;
        for(int i = 0 ; i < nd2.size() ; ++i)
            dp[nd2[i]][1] = val[nd2[i]];
        v.clear();
        v.insert(v.end() , nd1.begin() , nd1.end());
        v.insert(v.end() , nd2.begin() , nd2.end());
        bSort();
        //sort(v.begin() , v.end() , cmp1);
        top = 0;
        for(int i = 0 ; i < v.size() ; ++i){
            if(top){
                int p = LCA(st[top] , v[i]);
                while(dep[st[top - 1]] >= dep[p]){
                    ch[st[top - 1]].push_back(st[top]);
                    --top;
                }
                if(dep[st[top]] > dep[p]){
                    ch[p].push_back(st[top]);
                    st[top] = p;
                }
            }
            st[++top] = v[i];
        }
        while(top > 1){
            ch[st[top - 1]].push_back(st[top]);
            --top;
        }
        solve(st[1]);
        dp[st[1]][0] = dp[st[1]][1] = dp[0][0];
        top = 0;
    }
}

namespace Tree1{
    #define PII pair < int , int >
    #define st first
    #define nd second
    struct Edge{
        int end , upEd , w;
    }Ed[MAXN << 2];
    vector < PII > ch[MAXN];
    int head[MAXN << 1] , cntN , cntEd = 1 , nowSz , minSz , minInd;
    long long len[MAXN];
    
    inline void addEd(int a , int b , int c){
        Ed[++cntEd].end = b;
        Ed[cntEd].upEd = head[a];
        head[a] = cntEd;
        Ed[cntEd].w = c;
    }
    
    void rebuild(int x , int p){
        int cur = x;
        for(int i = 0 ; i < ch[x].size() ; ++i)
            if(ch[x][i].st != p){
                len[ch[x][i].st] = len[x] + ch[x][i].nd;
                int t = ++cntN;
                addEd(cur , t , 0);
                addEd(t , cur , 0);
                addEd(t , ch[x][i].st , ch[x][i].nd);
                addEd(ch[x][i].st , t , ch[x][i].nd);
                cur = t;
                rebuild(ch[x][i].st , x);
            }
    }
    
    void init(){
        for(int i = 1 ; i < N ; ++i){
            int a = read() , b = read() , c = read();
            ch[a].push_back(PII(b , c));
            ch[b].push_back(PII(a , c));
        }
        cntN = N;
        rebuild(1 , 0);
    }
    
    bool vis[MAXN << 1];
    void getSz(int x){
        vis[x] = 1;
        ++nowSz;
        for(int i = head[x] ; i ; i = Ed[i].upEd)
            if(!vis[Ed[i].end])
                getSz(Ed[i].end);
        vis[x] = 0;
    }
    
    int getRt(int x){
        vis[x] = 1;
        int sz = 1;
        for(int i = head[x] ; i ; i = Ed[i].upEd)
            if(!vis[Ed[i].end]){
                int t = getRt(Ed[i].end);
                if(minSz > max(t , nowSz - t)){
                    minSz = max(t , nowSz - t);
                    minInd = i;
                }
                sz += t;
            }
        vis[x] = 0;
        return sz;
    }
    
    void getNd(int x , long long l , vector < int > &v){
        if(x <= N){
            val[x] = l + len[x]; 
            v.push_back(x);
        } 
        vis[x] = 1;
        for(int i = head[x] ; i ; i = Ed[i].upEd)
            if(!vis[Ed[i].end])
                getNd(Ed[i].end , l + Ed[i].w , v);
        vis[x] = 0;
    }
    
    vector < int > nd1 , nd2;
    
    void solve(int x){
        nowSz = 0;
        minSz = 1e9;
        getSz(x);
        if(nowSz == 1)
            return;
        getRt(x);
        int p = Ed[minInd].end , q = Ed[minInd ^ 1].end;
        Ed[minInd].end = q;
        Ed[minInd ^ 1].end = p;
        nd1.clear();
        nd2.clear();
        getNd(p , 0 , nd1);
        getNd(q , 0 , nd2);
        if(nd1.size() && nd2.size())
            Tree2::work(nd1 , nd2 , Ed[minInd].w);
        solve(p);
        solve(q);
    }
    
    void work(){
        solve(1);
        for(int i = 1 ; i <= N ; ++i)
            ans = max(ans , len[i] - Tree2::len[i]);
    }
}

signed main(){
    #ifndef ONLINE_JUDGE
    freopen("in" , "r" , stdin);
    //freopen("out" , "w" , stdout);
    #endif
    N = read();
    Tree1::init();
    Tree2::init();
    Tree1::work();
    cout << ans;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Itst/p/10353143.html