zoukankan      html  css  js  c++  java
  • POJ 1741 Tree

    http://poj.org/problem?id=1741

    题目

    给一个有N个节点的树,每条边都有一个长度。两个节点之间的路径长度就是树上最短路径长度。问长度不超过k的路径一共有多少条。

    $Nleqslant 10000$

    题解

    树上分治,以p为根的树中路径有两种

    1.  从一个子树沿着向上,然后朝下进入另外一个子树

    2.  在p的同一个子树里面

    可以看出来,第二种情况仍然会经过一个根

    所以考虑第一种情况,然后递归考虑其他根的情况(转化为情况1)就可以了。

    题目要求路径长度不超过k,不能直接枚举(时间复杂度$n^2 imes n$,远远超过$10^9$),但是可以在遍历子树的时候寻找其他子树中剩余长度不超过$k-s$的节点数(不好写)

    还可以把节点排序,类似于双指针,当l增大时,r一定不会增大,并且保证$l<r$,同时统计l到r中剩余的每个子树节点的个数

    时间复杂度$mathcal{O}(R imes (n imes log n+n))$,如果只有一条链,那么$R=mathcal{O}(n)$,仍然会超时,因此需要每次递归都选择重心作为根,那么$R=mathcal{O}(log n)$

    时间复杂度$mathcal{O}(n imes log^2 n)$

    代码能力下降……又写了一下午

    AC代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #define REP(i,a,b) for(register int i=(a); i<(b); i++)
    #define REPE(i,a,b) for(register int i=(a); i<=(b); i++)
    using namespace std;
    #define MAXN 10007
    int n,k;
    int vis[MAXN];
    int sz[MAXN];
    int hd[MAXN], to[MAXN<<1], nxt[MAXN<<1], le[MAXN<<1], es;
    inline void init() {
    	es=0; memset(vis,0,sizeof vis); memset(hd,-1,sizeof(hd));
    	memset(sz,0,sizeof sz);
    }
    inline void adde(int a, int b, int c) {
    	nxt[es]=hd[a];hd[a]=es;to[es]=b;le[es]=c;es++;
    	nxt[es]=hd[b];hd[b]=es;to[es]=a;le[es]=c;es++;
    }
    //FINDS///////////////////////////////////////////////////
    int zd, hp, S;
    void dfsm(int p) {
    	vis[p]=1;
    	int s=1, mp=0;
    	for(int i=hd[p]; ~i; i=nxt[i]) if((!(vis[to[i]]&1)) && (!(vis[to[i]]&4))) {
    		dfsm(to[i]);
    		s+=sz[to[i]], mp=max(mp,sz[to[i]]);
    	}
    	mp = max(mp,S-s);
    	if(mp<zd) {
    		zd=mp, hp=p;
    	}
    	sz[p]=s;
    }
    void finds(int p, int s) {
    	zd=0x7fffffff;
    	S=s;
    	dfsm(p);
    }
    //GO//////////////////////////////////////////////////////
    struct node {
    	int l, b;
    	bool operator<(const node&r) const {
    		return l<r.l;
    	}
    } que[MAXN]; int qn; int cnt[MAXN];
    void go(int p, int b, int l) {
    	vis[p]=2;
    	que[qn++]=(node){l, b};
    	for(int i=hd[p]; ~i; i=nxt[i]) if((!(vis[to[i]]&2)) && (!(vis[to[i]]&4))){
    		go(to[i], b, l+le[i]);
    	}
    }
    //////////////////////////////////////////////////////////
    int ans;
    void calc(int p, int s) {
    	finds(p,s);
    	p=hp;
    	vis[p]=-1;
    	qn=0;
    	que[qn++]=(node){0,p};
    	for(int i=hd[p]; ~i; i=nxt[i]) if(!(vis[to[i]]&4)) {
    		go(to[i], to[i], le[i]);
    	}
    	memset(cnt,0,sizeof cnt);
    	REP(i,0,qn) {
    		cnt[que[i].b]++;
    	}
    	sort(que,que+qn);
    	int l=0, r=qn-1;
    	while(l<r) {
    		cnt[que[l].b]--;
    		while(l<r && que[l].l+que[r].l>k) {
    			cnt[que[r].b]--;
    			r--;
    		}
    		ans+=r-l-cnt[que[l].b];
    		l++;
    	}
    	for(int i=hd[p]; ~i; i=nxt[i]) if(!(vis[to[i]]&4)) {
    		calc(to[i], sz[to[i]]);
    	}
    }
    int main() {
    	while(~scanf("%d%d", &n, &k) && (n||k)) {
    		init(); ans=0;
    		REP(i,1,n) {
    			int a,b,c; scanf("%d%d%d", &a, &b, &c);
    			adde(a,b,c);
    		}
    		calc(1,n);
    		printf("%d
    ", ans);
    	}
    }
    
  • 相关阅读:
    初识人工智能(一):数据分析(三):numpy科学计算基础库(二)
    Python3标准库:urllib.parse分解URL
    Python3标准库:selectors I/O多路复用抽象
    Python3标准库:ipaddress Internet地址
    初识人工智能(一):数据分析(二):numpy科学计算基础库(一)
    Python3标准库:concurrent.futures管理并发任务池
    初识人工智能(一):数据分析(一):matplotlib绘图库
    Python3标准库:asyncio异步I/O、事件循环和并发工具
    Python3标准库:multiprocessing像线程一样管理进程
    Python3标准库:threading进程中管理并发操作
  • 原文地址:https://www.cnblogs.com/sahdsg/p/12256858.html
Copyright © 2011-2022 走看看