• 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)

    那么当前边贡献的答案就是(maxlimits_{i in L} maxlimits_{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;
    }
    
    
  • 相关阅读:
    libZPlay 音频编码解码器库
    C# PropertyGrid控件
    .netGDI+(转)
    (转)JITComplier、NGen.exe及.NET Native
    c# 特性/属性(Attribute) 以及使用反射查看自定义特性
    Fluent NHibernate系列文章
    Hibernate工作原理
    Orchard核心机制
    NHibernate和 FluentNHibernate
    极限编程之TDD
  • 原文地址:https://www.cnblogs.com/Itst/p/10353143.html
Copyright © 2020-2023  润新知