poj 1987 Distance Statistics 点分治
2016-07-19 17:09
423 查看
题目大意: 给你一棵树,问两个点对距离<=k的点对个数;
题目分析:点分治裸题。dfs处理出每个重心(分治下)到当前子树根节点的距离存在dis数组中,o(n)直接找出。
但要注意的是,对于dis所存的距离,只适用于两个不同的子树当中,所以要将位于同一个子树中的方案数减去。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#include<cmath>
#include<cctype>
#include<cassert>
#include<climits>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define RepD(i,n) for(int i=n;i>=0;i--)
#define MEM(a) memset(a,0,sizeof(a))
#define MEMI(a) memset(a,127,sizeof(a))
#define MEMi(a) memset(a,128,sizeof(a))
#define INF (2139062143)
#define phiF (1000000006)
#define MAXN (1000000+10)
typedef long long LL;
struct info{
int to,next,val;
bool use;
}e[100005];
int x,y,z,n,m,tot,first[100005],son[50005],f[50005],size,root,a[50005],dis[50005],k,ans;
void add(int x,int y,int z){
e[tot].to=y;
e[tot].val=z;
e[tot].next=first[x];
first[x]=tot;tot++;
}
void findroot(int u,int fa){
son[u]=1;f[u]=0;
for (int p=first[u];p!=-1;p=e[p].next){
int v=e[p].to;
if (v==fa) continue;
if (e[p].use) continue;
findroot(v,u);
f[u]=max(f[u],son[v]);
son[u]+=son[v];
}
f[u]=max(f[u],size-son[u]);
if (f[u]<f[root]) root=u;
}
void dfs(int u,int fa){
son[u]=1;
a[++a[0]]=dis[u];
for (int p=first[u];p!=-1;p=e[p].next){
int v=e[p].to;
if (!e[p].use&&v!=fa){
dis[v]=dis[u]+e[p].val;
dfs(v,u);
son[u]+=son[v];
}
}
}
int count(int u,int val){
int tmp=a[0]=0;
dis[u]=val;
dfs(u,0);
sort(a+1,a+a[0]+1);
for (int l=1,r=a[0];l<r;){
if (a[l]+a[r]<=k){
tmp+=r-l;l++;
} else r--;
}
return tmp;
}
void work(int u){
ans+=count(u,0);
for (int p=first[u];p!=-1;p=e[p].next){
if (!e[p].use){
e[p^1].use=true;
ans-=count(e[p].to,e[p].val);
f[0]=size=son[e[p].to];root=0;
findroot(e[p].to,0);
work(root);
}
}
}
char ch;
int main(){
memset(first,-1,sizeof(first));
scanf("%d%d",&n,&m);
For (i,m){
scanf("%d%d%d %c",&x,&y,&z,&ch);
add(x,y,z);
add(y,x,z);
}
scanf("%d",&k);
f[0]=size=n;
findroot(1,0);
work(root);
printf("%d",ans);
}
题目分析:点分治裸题。dfs处理出每个重心(分治下)到当前子树根节点的距离存在dis数组中,o(n)直接找出。
但要注意的是,对于dis所存的距离,只适用于两个不同的子树当中,所以要将位于同一个子树中的方案数减去。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#include<cmath>
#include<cctype>
#include<cassert>
#include<climits>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define RepD(i,n) for(int i=n;i>=0;i--)
#define MEM(a) memset(a,0,sizeof(a))
#define MEMI(a) memset(a,127,sizeof(a))
#define MEMi(a) memset(a,128,sizeof(a))
#define INF (2139062143)
#define phiF (1000000006)
#define MAXN (1000000+10)
typedef long long LL;
struct info{
int to,next,val;
bool use;
}e[100005];
int x,y,z,n,m,tot,first[100005],son[50005],f[50005],size,root,a[50005],dis[50005],k,ans;
void add(int x,int y,int z){
e[tot].to=y;
e[tot].val=z;
e[tot].next=first[x];
first[x]=tot;tot++;
}
void findroot(int u,int fa){
son[u]=1;f[u]=0;
for (int p=first[u];p!=-1;p=e[p].next){
int v=e[p].to;
if (v==fa) continue;
if (e[p].use) continue;
findroot(v,u);
f[u]=max(f[u],son[v]);
son[u]+=son[v];
}
f[u]=max(f[u],size-son[u]);
if (f[u]<f[root]) root=u;
}
void dfs(int u,int fa){
son[u]=1;
a[++a[0]]=dis[u];
for (int p=first[u];p!=-1;p=e[p].next){
int v=e[p].to;
if (!e[p].use&&v!=fa){
dis[v]=dis[u]+e[p].val;
dfs(v,u);
son[u]+=son[v];
}
}
}
int count(int u,int val){
int tmp=a[0]=0;
dis[u]=val;
dfs(u,0);
sort(a+1,a+a[0]+1);
for (int l=1,r=a[0];l<r;){
if (a[l]+a[r]<=k){
tmp+=r-l;l++;
} else r--;
}
return tmp;
}
void work(int u){
ans+=count(u,0);
for (int p=first[u];p!=-1;p=e[p].next){
if (!e[p].use){
e[p^1].use=true;
ans-=count(e[p].to,e[p].val);
f[0]=size=son[e[p].to];root=0;
findroot(e[p].to,0);
work(root);
}
}
}
char ch;
int main(){
memset(first,-1,sizeof(first));
scanf("%d%d",&n,&m);
For (i,m){
scanf("%d%d%d %c",&x,&y,&z,&ch);
add(x,y,z);
add(y,x,z);
}
scanf("%d",&k);
f[0]=size=n;
findroot(1,0);
work(root);
printf("%d",ans);
}
相关文章推荐
- 初学ACM - 组合数学基础题目PKU 1833
- POJ ACM 1001
- POJ ACM 1002
- 1611:The Suspects
- POJ1089 区间合并
- POJ 2159 Ancient Cipher
- POJ 2635 The Embarrassed Cryptographe
- POJ 3292 Semi-prime H-numbers
- POJ 2773 HAPPY 2006
- POJ 3090 Visible Lattice Points
- POJ-2409-Let it Bead&&NYOJ-280-LK的项链
- POJ-1695-Magazine Delivery-dp
- POJ1523 SPF dfs
- POJ-1001 求高精度幂-大数乘法系列
- POJ-1003 Hangover
- POJ-1004 Financial Management
- [数论]poj2635__The Embarrassed Cryptographer
- [二分图匹配]poj2446__Chessboard
- POJ1050 最大子矩阵和
- 用单调栈解决最大连续矩形面积问题