点分治

能力不足,待填坑
P3676 小清新数据结构题
P2664 树上游戏

用于求树上的满足条件的点对个数
例如最基本的求树上所有满足x到y的距离为k,是k的倍数等等的点对个数

模板

#include<iostream>//注意此模板点的下标应为1到n!!!
#include<cstdio>
#include<vector>
using namespace std;
const int MAX_N=20100; 
const int INF=0x3f3f3f3f;
int son[MAX_N],max_son[MAX_N],dis[MAX_N];
bool vis[MAX_N];
long long ans=0;
int root;
int cnt,sum;
vector<int>v[MAX_N],w[MAX_N];
void dfs(int now,int fa){
    int i;
    son[now]=1;
    max_son[now]=0;
    for(i=0;i<v[now].size();i++){
        int to=v[now][i];
        if(to==fa||vis[to])
        continue;
        dfs(to,now);
        son[now]+=son[to];
        max_son[now]=max(max_son[now],son[to]);
    }
    max_son[now]=max(max_son[now],sum-son[now]);
    if(max_son[now]<max_son[root])
    root=now;
}
void getdis(int now,int fa,int d){
    int i;
    dis[++cnt]=d;
    for(i=0;i<v[now].size();i++){
        int to=v[now][i];
        if(to==fa||vis[to])
        continue;
        getdis(to,now,d+w[now][i]);
    }
}
int Calc(int now,int d){
    int i,j;
    int res=0;
    cnt=0;
    getdis(now,0,d);
    //从now点出发的所有点都储存在dis数组中,为[1,cnt]。
    //每个点最多被分治log次,复杂度为logn*T,T为Calc的复杂度。
}
void divide(int now){
    int i;
    ans+=Calc(now,0);
    vis[now]=true;
    for(i=0;i<v[now].size();i++){
        int to=v[now][i];
        if(vis[to])
        continue;
        ans-=Calc(to,w[now][i]);
        sum=son[to];
        root=0;
        dfs(to,0);
        divide(root);
    }
}
int main(void){
    int n,i,a,b,c;
    scanf("%d",&n);
    for(i=1;i<n;i++){
        scanf("%d%d%d",&a,&b,&c);
        v[a].push_back(b);
        w[a].push_back(c);
        v[b].push_back(a);
        w[b].push_back(c);
    }
    sum=n;
    max_son[0]=n;
    root=0;
    dfs(1,0);
    divide(root);
    //ans
    return 0;
}

P2634 [国家集训队]聪聪可可

#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
const int MAX_N=20100; 
const int INF=0x3f3f3f3f;
int son[MAX_N],max_son[MAX_N],dis[MAX_N];
bool vis[MAX_N];
long long ans=0;
int root;
int cnt,sum;
vector<int>v[MAX_N],w[MAX_N];
void dfs(int now,int fa){
	int i;
	son[now]=1;
	max_son[now]=0;
	for(i=0;i<v[now].size();i++){
		int to=v[now][i];
		if(to==fa||vis[to])
		continue;
		dfs(to,now);
		son[now]+=son[to];
		max_son[now]=max(max_son[now],son[to]);
	}
	max_son[now]=max(max_son[now],sum-son[now]);
	if(max_son[now]<max_son[root])
    root=now;
}
void getdis(int now,int fa,int d){
	int i;
	dis[++cnt]=d;
	for(i=0;i<v[now].size();i++){
		int to=v[now][i];
		if(to==fa||vis[to])
		continue;
		getdis(to,now,d+w[now][i]);
	}
}
void solve(int now,int d,int k){
	int i,j;
	cnt=0;
	getdis(now,0,d);
	long long a[3]={0};
	for(i=1;i<=cnt;i++){
		a[dis[i]%3]+=1;
	}
	ans+=k*(a[0]*a[0]+a[1]*a[2]+a[2]*a[1]);
}
void divide(int now){
	int i;
	solve(now,0,1);
	vis[now]=true;
	for(i=0;i<v[now].size();i++){
		int to=v[now][i];
		if(vis[to])
		continue;
		solve(to,w[now][i],-1);
		sum=son[to];
		root=0;
		dfs(to,0);
		divide(root);
	}
}
long long gcd(long long a,long long b){
	return b?gcd(b,a%b):a;
}
int main(void){
	int n,i,a,b,c;
	scanf("%d",&n);
	for(i=1;i<n;i++){
		scanf("%d%d%d",&a,&b,&c);
		v[a].push_back(b);
		w[a].push_back(c);
		v[b].push_back(a);
		w[b].push_back(c);
	}
	sum=n;
	max_son[0]=n;
	root=0;
	dfs(1,0);
	divide(root);
	long long x=n*n;
	//cout<<ans<<" "<<x<<"\n";
	long long g=gcd(x,ans);
	printf("%lld/%lld\n",ans/g,x/g);
	return 0;
}

P3806 【模板】点分治1

#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
const int MAX_N=20100; 
const int INF=0x3f3f3f3f;
int have[10010000];
int son[MAX_N],max_son[MAX_N],dis[MAX_N];
bool vis[MAX_N];
long long ans=0;
int root;
int cnt,sum;
vector<int>v[MAX_N],w[MAX_N];
void dfs(int now,int fa){
	int i;
	son[now]=1;
	max_son[now]=0;
	for(i=0;i<v[now].size();i++){
		int to=v[now][i];
		if(to==fa||vis[to])
		continue;
		dfs(to,now);
		son[now]+=son[to];
		max_son[now]=max(max_son[now],son[to]);
	}
	max_son[now]=max(max_son[now],sum-son[now]);
	if(max_son[now]<max_son[root])
    root=now;
}
void getdis(int now,int fa,int d){
	int i;
	dis[++cnt]=d;
	for(i=0;i<v[now].size();i++){
		int to=v[now][i];
		if(to==fa||vis[to])
		continue;
		getdis(to,now,d+w[now][i]);
	}
}
void solve(int now,int d,int k){
	int i,j;
	cnt=0;
	getdis(now,0,d);
	for(i=1;i<=cnt;i++){
		for(j=1;j<=cnt;j++){
			have[dis[i]+dis[j]]+=k;
		}
	}
}
void divide(int now){
	int i;
	solve(now,0,1);
	vis[now]=true;
	for(i=0;i<v[now].size();i++){
		int to=v[now][i];
		if(vis[to])
		continue;
		solve(to,w[now][i],-1);
		sum=son[to];
		root=0;
		dfs(to,0);
		divide(root);
	}
}
int main(void){
	int n,i,a,b,c,m,k;
	scanf("%d%d",&n,&m);
	for(i=1;i<n;i++){
		scanf("%d%d%d",&a,&b,&c);
		v[a].push_back(b);
		w[a].push_back(c);
		v[b].push_back(a);
		w[b].push_back(c);
	}
	sum=n;
	max_son[0]=n;
	root=0;
	dfs(1,0);
	divide(root);
	for(i=0;i<m;i++){
		scanf("%d",&k);
		if(have[k]!=0)
		cout<<"AYE\n";
		else
		cout<<"NAY\n";
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值