zoukankan      html  css  js  c++  java
  • HDU 树型dp

    HDU 4123 Bob's Race

    题意:定义每个点的值为它到树上最远点的距离,每次询问q,回答最长的极值差小于等于q且编号连续的一段点的长度。
    题解:求距离两次dp,求极值ST表+尺取法。

    HDU 4514 湫湫系列故事——设计风景线

    题意:给一张图,如果有环,输出YES,否则为一个森林,求出每个树的直径,输出最大值。
    题解:并查集判环,两边dfs找直径。

    POJ 1655 Balancing Act

    题意:删掉一个点,使得分出的最大连通块大小最小
    题解:求重儿子,用重儿子大小和(n-sze[该子树])去更新答案。

    HDU 4714 Tree2cycle

    题意:删边或加边都有1的费用,求将一棵树变成一个环的最小费用。
    题解:贪心:将树拆成链再连成环。具体:对树进行dfs,如果一个节点有大于等于2个子节点,就删边保留两个子节点,并删除该节点与父亲的连边(特判根节点),最后答案为删边*2+1(连接图的首尾)。

    code

    hdu4123

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    #define maxn 50050
    #define maxm 550
    #define oo 0x3f3f3f3f
    int n, m;
    int ecnt, adj[maxn], go[maxn*2], len[maxn*2], nxt[maxn*2];
    int dp[maxn][5];  //0向下最大,1向下次大,2向上最大
    int delta[maxn], Log[25], ans;
    int mx[maxn][25], mn[maxn][25];
    
    inline void initLog() {
    	Log[0] = -1;
    	for(int i = 1; i <= 50005; i++) Log[i] = Log[i >> 1] + 1;
    }
    
    inline void addEdge(int u, int v, int c) {
    	nxt[++ecnt] = adj[u], adj[u] = ecnt, go[ecnt] = v, len[ecnt] = c;
    }
    
    inline void init() {
    	for(int i = 1; i <= n; i++) adj[i] = 0;
    	ecnt = 0;
    	for(int i = 1; i <= n; i++) {
    		dp[i][0] = dp[i][1] = 0;
    		dp[i][2] = 0;
    	}
    }
    
    inline void dfs1(int u, int f) {
    	for(int e = adj[u]; e; e = nxt[e]) {
    		int v = go[e];
    		if(v == f) continue;
    		dfs1(v, u);
    		if(dp[v][0] + len[e] > dp[u][0]) {
    			dp[u][1] = dp[u][0];
    			dp[u][0] = dp[v][0] + len[e];
    		} else if(dp[v][0] + len[e] > dp[u][1]) {
    			dp[u][1] = dp[v][0] + len[e];
    		}
    	}
    }
    
    inline void dfs2(int u, int f) {
    	for(int e = adj[u]; e; e = nxt[e]) {
    		int v = go[e];
    		if(v == f) continue;
    		int t = ((dp[u][0] == dp[v][0] + len[e]) ? dp[u][1] : dp[u][0]);
    		dp[v][2] = max(t + len[e], dp[u][2] + len[e]);
    		dfs2(v, u);
    	}
    }
    
    inline int query(int l, int r){
    	int k = Log[r - l + 1];
    	int maxx = max(mx[l][k], mx[r - (1 << k) + 1][k]);
    	int minn = min(mn[l][k], mn[r - (1 << k) + 1][k]);
    	return maxx - minn;
    }
    
    int main() {
    	initLog();
    	while(scanf("%d%d", &n, &m) != EOF) {
    		if(!n && !m) return 0;
    		init();
    		for(int i = 1; i < n; i++) {
    			int x, y, z;
    			scanf("%d%d%d", &x, &y, &z);
    			addEdge(x, y, z);
    			addEdge(y, x, z);
    		}
    		dfs1(1, 0);
    		dfs2(1, 0);
    //		for(int i = 1; i <= n; i++) cout<<i<<" "<<dp[i][0]<<" "<<dp[i][1]<<" "<<dp[i][2]<<endl;
    		for(int i = 1; i <= n; i++) mx[i][0] = mn[i][0] = max(dp[i][0], dp[i][2]);
    		for(int j = 1; j <= Log[n]; j++)
    			for(int i = 1; i <= n; i++){
    				if(i + (1 << j) - 1 <= n){
    					mx[i][j] = max(mx[i][j - 1], mx[i + (1 << (j - 1))][j - 1]);
    					mn[i][j] = min(mn[i][j - 1], mn[i + (1 << (j - 1))][j - 1]);
    				}
    			}
    		for(int i = 1; i <= m; i++) {
    			int q, ans = 0;
    			scanf("%d", &q);
    			int head = 1;
    			for(int j = 1; j <= n; j++) {
    				while(head <= j && query(head, j) > q) head++;
    				ans = max(ans, j - head + 1);
    			}
    			printf("%d
    ",ans);
    		}
    	}
    }
    

    hdu4514

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    const int N = 100050, M = 1000050;
    int n, m;
    int ecnt, adj[N], go[M << 1], nxt[M << 1], len[M << 1];
    int vst[N], vt, anc[N], pos1, pos2, dis, ans;
    
    inline void addEdge(int u, int v, int l){
    	nxt[++ecnt] = adj[u], adj[u] = ecnt, go[ecnt] = v, len[ecnt] = l;
    }
    
    inline void dfs(int u, int f, int l, int &pos){
    	vst[u] = vt;
    	if(l > dis){
    		pos = u;
    		dis = l;
    	}
    	for(int e = adj[u]; e; e = nxt[e]){
    		int v = go[e];
    		if(v == f) continue;
    		dfs(v, u, l + len[e], pos);
    	}
    }
    
    inline int getAnc(int x){
    	return x == anc[x] ? x :(anc[x] = getAnc(anc[x]));
    }
    
    int main(){
    	while(~scanf("%d%d", &n, &m)){
    		for(int i = 1; i <= n; i++) anc[i] = i, adj[i] = 0; ecnt = ans = 0;
    		bool flag = true;
    		for(int i = 1; i <= m; i++){
    			int x, y, z; scanf("%d%d%d", &x, &y, &z);
    			if(!flag) continue;
    			int fx = getAnc(x), fy = getAnc(y); 
    			if(fx == fy) flag = false;
    			if(flag) addEdge(x, y, z), addEdge(y, x, z), anc[fx] = fy;
    		}
    		if(!flag){
    			printf("YES
    ");
    			continue;
    		}
    		vt++;
    		for(int i = 1; i <= n; i++){
    			if(vst[i] == vt) continue;
    			dis = 0, pos1 = 0, pos2 = 0;
    			dfs(i, 0, 0, pos1);
    			dis = 0;
    			dfs(pos1, 0, 0, pos2);
    			ans = max(dis, ans);
    		}
    		printf("%d
    ", ans);
    	}
    }
    

    poj1655
    待填

    hdu4714

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    inline int read(){
    	int i = 0, f = 1; char ch = getchar();
    	for(; (ch < '0' || ch > '9') && ch != '-'; ch = getchar());
    	if(ch == '-') f = -1, ch = getchar();
    	for(; ch >= '0' && ch <= '9'; ch = getchar()) i = (i << 3) + (i << 1) + (ch - '0');
    	return i * f;
    }
    
    inline void wr(int x){
    	if(x < 0) putchar('-'), x = -x;
    	if(x > 9) wr(x / 10);
    	putchar(x % 10 + '0');
    }
    const int N = 1000050;
    int T, n;
    int ecnt, adj[N], go[N << 1], nxt[N << 1], cnt;
    
    inline void addEdge(int u, int v){
    	nxt[++ecnt] = adj[u], adj[u] = ecnt, go[ecnt] = v;
    }
    
    inline int dfs(int u, int f){
    	int ret = 0;
    	for(int e = adj[u]; e; e = nxt[e]){
    		int v = go[e];
    		if(v == f) continue;
    		ret += dfs(v, u);
    	}
    	if(ret >= 2){
    		cnt += ret - 2 + (u == 1 ? 0 : 1);
    		return 0;    //删去与父亲节点的边 
    	}
    	return 1;
    }
    
    int main(){
    	T = read();
    	while(T--){
    		n = read();
    		for(int i = 1; i <= n; i++) adj[i] = 0; ecnt = 0;
    		for(int i = 1; i < n; i++){
    			int x = read(), y = read();
    			addEdge(x, y);
    			addEdge(y, x);
    		}
    		cnt = 0;
    		dfs(1, 0);
    		wr(cnt * 2 + 1);
    		putchar('
    ');
    	}
    }
    
  • 相关阅读:
    网页的资源加载优化
    Object.prototype.toString的应用
    判断一个字符串中出现次数最多的字符,并统计字数
    toString()和toLocaleString()有什么区别
    响应式网站布局要适应的当下主流手机屏幕的各个版本的分辨率有哪些(media query)
    handlebars用法
    算符优先分析及其简单代码实现
    OpenGL:使用顶点数组法绘制正六面体
    算法设计:两种快速排序代码实现
    c#简易学生信息管理系统
  • 原文地址:https://www.cnblogs.com/CzYoL/p/7726507.html
Copyright © 2011-2022 走看看