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;
}

posted @ 2019-02-05 21:08  cjoier_Itst  阅读(272)  评论(0编辑  收藏  举报