zoukankan      html  css  js  c++  java
  • P4178 Tree

    (color{#0066ff}{题目描述})

    给你一棵TREE,以及这棵树上边的距离.问有多少对点它们两者间的距离小于等于K

    (color{#0066ff}{输入格式})

    N(n<=40000) 接下来n-1行边描述管道,按照题目中写的输入 接下来是k

    (color{#0066ff}{输出格式})

    一行,有多少对点之间的距离小于等于k

    (color{#0066ff}{输入样例})

    7
    1 6 13 
    6 3 9 
    3 5 7 
    4 1 3 
    2 4 20 
    4 7 2 
    10
    

    (color{#0066ff}{输出样例})

    5
    

    (color{#0066ff}{数据范围与提示})

    none

    (color{#0066ff}{题解})

    点分治

    拆掉重心,对子树操作

    维护一个权值树状数组

    搜完一棵子树,把所有的dis放到一个数组里

    for在树状数组上统计答案(注意要+1,那是当前点与重心的点对贡献)

    之后把当前子树加入树状数组,最后清空

    #include<bits/stdc++.h>
    using namespace std;
    #define LL long long
    LL in() {
    	char ch; int x = 0, f = 1;
    	while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
    	for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
    	return x * f;
    }
    struct node {
    	int to, dis;
    	node *nxt;
    	node(int to = 0, int dis = 0, node *nxt = NULL): to(to), dis(dis), nxt(nxt) {}
    	void *operator new (size_t) {
    		static node *S = NULL, *T = NULL;
    		return (S == T) && (T = (S = new node[1024]) + 1024), S++;
    	}
    };
    const int maxn = 40505;
    int siz[maxn], f[maxn], tmp[maxn], ls[maxn];
    node *head[maxn];
    bool vis[maxn];
    int n, k, num, cnt, sum, root;
    int ans;
    struct BIT {
    protected:
    	int st[maxn];
    	int low(int x) { return x & (-x); }
    public:
    	void add(int pos, int x) { while(pos <= k) st[pos] += x, pos += low(pos); }
    	int query(int pos) { int re = 0; while(pos) re += st[pos], pos -= low(pos); return re; }
    }b;
    void add(int from, int to, int dis) {
    	head[from] = new node(to, dis, head[from]);
    }
    void getdis(int x, int fa, int dis) {
    	ls[++cnt] = dis;
    	for(node *i = head[x]; i; i = i->nxt) 
    		if(i->to != fa && !vis[i->to])
    			getdis(i->to, x, dis + i->dis);
    }
    void getroot(int x, int fa) {
    	f[x] = 0, siz[x] = 1;
    	for(node *i = head[x]; i; i = i->nxt) {
    		if(vis[i->to] || i->to == fa) continue;
    		getroot(i->to, x);
    		siz[x] += siz[i->to];
    		f[x] = std::max(f[x], siz[i->to]);
    	}
    	f[x] = std::max(f[x], sum - siz[x]);
    	if(f[x] < f[root]) root = x;
    }
    void calc(int x) {
    	num = 0;
    	for(node *i = head[x]; i; i = i->nxt) {
    		if(vis[i->to]) continue;
    		cnt = 0;
    		getdis(i->to, 0, i->dis);
    		for(int j = 1; j <= cnt; j++) if(ls[j] <= k) ans += b.query(k - ls[j]) + 1;
    		for(int j = 1; j <= cnt; j++) if(ls[j] <= k) b.add(ls[j], 1), tmp[++num] = ls[j];
    	}
    	for(int i = 1; i <= num; i++) b.add(tmp[i], -1);
    }
    
    void work(int x) {
    	vis[x] = true;
    	calc(x);
    	for(node *i = head[x]; i; i = i->nxt) {
    		if(vis[i->to]) continue;
    		root = 0, sum = siz[i->to];
    		getroot(i->to, 0);
    		work(root);
    	}
    }
    int main() {
    	n = in();
    	int x, y, z;
    	for(int i = 1; i < n; i++) {
    		x = in(), y = in(), z = in();
    		add(x, y, z), add(y, x, z);
    	}
    	k = in();
    	f[0] = sum = n;
    	getroot(1, 0); 
    	work(root);
    	printf("%d", ans);
    	return 0;
    }
    
  • 相关阅读:
    java多线程(同步与死锁问题,生产者与消费者问题)
    剑指OFFER之跳台阶(九度OJ1388)
    剑指OFFER之二维数组中的查找(九度OJ1384)
    剑指OFFER之旋转数组的最小数字(九度OJ1386)
    我所思考的生活,致半年后的自己
    剑指OFFER之用两个栈实现队列(九度OJ1512)
    剑指OFFER之二维数组中的查找(九度OJ1384)
    剑指OFFER之重建二叉树(九度OJ1385)
    简单的客户机服务器投射模拟
    网络复习之TCP
  • 原文地址:https://www.cnblogs.com/olinr/p/10208635.html
Copyright © 2011-2022 走看看