点分治中重点需要注意:
- 统计ans的时候,一定要注意子树中的ans和当前根节点的ans的处理关系
- 切记要注意重心的处理
一、P3806 【模板】点分治1
思路:
- 将一颗子树的点到根的距离存入到一个栈中,这个栈维护当前重心的所有子树的距离信息
- 我们在得子树点到根信息后,我们在枚举进行距离的判断,我们判断完再进行信息的入栈。
code:
/*
* @Author: 0iq_love_zy
* @LastEditTime: 2021-02-21 18:35:44
* @CSDN blog: https://blog.csdn.net/acm_durante
* @E-mail: 1055323152@qq.com
* @ProbTitle:
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, a, n) for (int i = n; i >= a; i--)
#define lowbit(x) ((x) & -(x))
#define lson p << 1 , l, mid
#define rson p << 1 | 1, mid + 1, r
#define mem(a, b) memset(a, b, sizeof(a))
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const double PI = acos(-1.0);
const int N = 2e4+5,M = 1e7+5;
int n,m,ask[105],cnt,head[N];
struct node{
int v,w,net;
}e[N];
void add(int u,int v,int w){
e[++cnt].v = v;
e[cnt].w = w;
e[cnt].net = head[u];
head[u] = cnt;
}
int sz[N],sum,mx[N],root;
bool vis[N];
void get_root(int u,int fa){
sz[u] = 1;
mx[u] = 0;
for(int i = head[u]; ~i ; i = e[i].net){
int v = e[i].v;
if(vis[v] || v == fa) continue;
get_root(v,u);
sz[u] += sz[v];
mx[u] = max(mx[u],sz[v]);
}
mx[u] = max(mx[u],sum - mx[u]);
if(mx[u] < mx[root]){
root = u;
}
}
int dis[N],dd[N],tot;
void get_dis(int u,int fa){
dd[++tot] = dis[u];
for(int i = head[u]; ~i ; i = e[i].net){
int v = e[i].v, w = e[i].w;
if(v == fa || vis[v]) continue;
dis[v] = dis[u] + w;
get_dis(v,u);
}
}
queue<int>que;
bool tf[M],ans[M];
void dfz(int u,int fa){
tf[0] = 1;
que.push(0);
vis[u] = 1;
for(int i = head[u]; ~i ; i = e[i].net){//case1:经过u
int v = e[i].v;
if(v == fa || vis[v]) continue;
dis[v] = e[i].w;
tot = 0;
get_dis(v,u);
rep(j,1,tot)
rep(z,1,m){
if(ask[z] >= dd[j]) ans[z] |= tf[ask[z] - dd[j]];
}
rep(j,1,tot){
if(dd[j] <= 1e7){
tf[dd[j]] = 1;
que.push(dd[j]);
}
}
}
while(!que.empty()){//清空
tf[que.front()] = 0;
que.pop();
}
for(int i = head[u]; ~i ; i = e[i].net){
int v = e[i].v;
if(vis[v] || v == fa) continue;
sum = sz[v];
root = 0;
mx[root] = 2e9;
get_root(v,u);
get_root(root,-1);
dfz(root,u);
}
}
int main()
{
IOS
mem(head,-1);
cin >> n >> m;
rep(i,1,n-1){
int u,v,w;
cin >> u >> v >> w;
add(u,v,w);
add(v,u,w);
}
rep(i,1,m) cin >> ask[i];
sum = n;
root = 0;
mx[0] = 2e9;
get_root(1,-1);
get_root(root,-1);
dfz(root,-1);
rep(i,1,m){
if(ans[i]) cout << "AYE\n";
else cout << "NAY\n";
}
return 0;
}
二、VK Cup 2012 Round 1 D. Distance in Tree
求距离为k的点对个数
思路:
- 本题我们用二分来处理答案的统计做到n*log(n)的时间复杂度来得到答案
- 注意处理点时两个点若在一个子树上的问题
code
/*
* @Author: 0iq_love_zy
* @LastEditTime: 2021-02-22 17:43:13
* @CSDN blog: https://blog.csdn.net/acm_durante
* @E-mail: 1055323152@qq.com
* @ProbTitle:
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, a, n) for (int i = n; i >= a; i--)
#define lowbit(x) ((x) & -(x))
#define lson p << 1 , l, mid
#define rson p << 1 | 1, mid + 1, r
#define mem(a, b) memset(a, b, sizeof(a))
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const double PI = acos(-1.0);
const int N = 100500;
int n,k;
vector<int>e[N];
int mx[N],sz[N],root,S;
bool vis[N];
ll ans = 0;
void get_root(int u,int fa){
mx[u] = 0;
sz[u] = 1;
for(auto v:e[u]){
if(vis[v] || v == fa) continue;
get_root(v,u);
sz[u] += sz[v];
mx[u] = max(mx[u],sz[v]);
}
mx[u] = max(mx[u],S - mx[u]);
if(mx[u] < mx[root]) root = u;
}
int dis[N],dd[N],cnt;
void get_dis(int u,int fa,int di){
for(auto v:e[u]){
if(v == fa || vis[v]) continue;
dd[++cnt] = di + 1;
get_dis(v,u,dd[cnt]);
}
}
ll get_ans(int u,int fa,int di){
ll res = 0;
cnt = 1;
dd[cnt] = di;
get_dis(u,fa,di);
sort(dd+1,dd+1+cnt);
for(int i = 1 ; i <= cnt ; i++){
int pos1 = lower_bound(dd + i + 1,dd + cnt + 1,k - dd[i]) - dd;//二分处理相同dis的个数
int pos2 = upper_bound(dd + i + 1,dd + cnt + 1,k - dd[i]) - dd;
res += pos2 - pos1;
}
return res;
}
void dfz(int u,int fa){
vis[u] = 1, ans += get_ans(u,fa,0);
for(auto v:e[u]){
if(vis[v] || v == fa) continue;
ans -= get_ans(v,u,1);
S = sz[v];
root = 0;
mx[root] = INT_MAX;
get_root(v,u);
get_root(root,-1);
dfz(root,-1);
}
}
int main()
{
IOS
cin >> n >> k;
rep(i,1,n-1){
int u,v;
cin >> u >> v;
e[u].push_back(v);
e[v].push_back(u);
}
root = 0;
S = n;
mx[root] = INT_MAX;
get_root(1,-1);
get_root(root,-1);
dfz(root,-1);
cout << ans << "\n";
return 0;
}
三、洛谷 P4178 Tree
求小于k的点对个数
思路:
- 和上题一样,但是需要注意我们来统计答案时,我们可以寻找k-dis的最大值的位置,在这个位置之前的都符合答案
code:
/*
* @Author: 0iq_love_zy
* @LastEditTime: 2021-02-23 10:53:30
* @CSDN blog: https://blog.csdn.net/acm_durante
* @E-mail: 1055323152@qq.com
* @ProbTitle:
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, a, n) for (int i = n; i >= a; i--)
#define lowbit(x) ((x) & -(x))
#define lson p << 1 , l, mid
#define rson p << 1 | 1, mid + 1, r
#define mem(a, b) memset(a, b, sizeof(a))
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const double PI = acos(-1.0);
const int N = 4e4+10;
struct node{
int v,w;
};
vector<node>e[N];
int n,k;
int sz[N],mx[N],root,S;
bool vis[N];
void get_root(int u,int fa){
mx[u] = 0;
sz[u] = 1;
for(auto i:e[u]){
int v = i.v;
if(vis[v] || v == fa) continue;
get_root(v,u);
sz[u] += sz[v];
mx[u] = max(mx[u], sz[v]);
}
mx[u] = max(mx[u], S - mx[u]);
if(mx[u] < mx[root]) root = u;
}
int dd[N],tot;
void get_dis(int u,int fa,int d){
for(auto i:e[u]){
int v = i.v, w = i.w;
if(v == fa || vis[v]) continue;
dd[++tot] = d + w;
get_dis(v,u,dd[tot]);
}
}
ll calc(int u,int fa,int d){
tot = 1;
dd[tot] = d;
get_dis(u,fa,d);
sort(dd+1,dd+1+tot);
ll res = 0;
for(int i = 1; i <= tot; i++){
if(dd[i] > k) break;
int l = i + 1;
int r = upper_bound(dd + 1 + i,dd + 1 + tot,k - dd[i]) - dd;
res += r - l;
}
return res;
}
ll ans = 0;
void dfz(int u,int fa){
vis[u] = 1;
ans += calc(u,fa,0);
for(auto i:e[u]){
int v = i.v;
if(vis[v] || v == fa) continue;
ans -= calc(v,u,i.w);
root = 0;
mx[root] = INT_MAX;
S = sz[v];
get_root(v,u);
get_root(root,-1);
dfz(root,-1);
}
}
int main()
{
IOS
cin >> n;
rep(i,1,n-1){
int u,v,w;
cin >> u >> v >> w;
e[u].push_back({v,w});
e[v].push_back({u,w});
}
cin >> k;
S = n;
root = 0;
mx[root] = INT_MAX;
get_root(1,-1);
get_root(root,-1);
//cout << root << endl;
dfz(root,-1);
cout << ans;
return 0;
}
四、P2634 [国家集训队]聪聪可可
**思路:**记录答案时,模3处理就行
code:
/*
* @Author: 0iq_love_zy
* @LastEditTime: 2021-02-24 10:07:44
* @CSDN blog: https://blog.csdn.net/acm_durante
* @E-mail: 1055323152@qq.com
* @ProbTitle:
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, a, n) for (int i = n; i >= a; i--)
#define lowbit(x) ((x) & -(x))
#define lson p << 1 , l, mid
#define rson p << 1 | 1, mid + 1, r
#define mem(a, b) memset(a, b, sizeof(a))
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const double PI = acos(-1.0);
const int N = 2e4+50;
struct node{
int v,w;
};
vector<node>e[N];
int n,S,root,sz[N],mx[N];
bool vis[N];
void get_root(int u,int fa){
mx[u] = 0;
sz[u] = 1;
for(auto i:e[u]){
int v = i.v;
if(vis[v] || v == fa) continue;
get_root(v,u);
sz[u] += sz[v];
mx[u] = max(mx[u],sz[v]);
}
mx[u] = max(mx[u],S - mx[u]);
if(mx[u] < mx[root]) root = u;
}
int dd[N],tot;
ll ans;
void get_dis(int u,int fa,int di){
for(auto i:e[u]){
int v = i.v, w = i.w;
if(vis[v] || v == fa) continue;
dd[++tot] = (di + w) % 3;
get_dis(v,u,dd[tot]);
}
}
ll cnt[4];
ll calc(int u,int fa,int di){
dd[tot = 1] = di % 3;
get_dis(u,fa,di);
sort(dd+1,dd+1+tot);
mem(cnt,0);
ll res = 0;
for(int i = 1; i <= tot ; i++){
cnt[dd[i]]++;
}
//cout << "u = " << u << " fa = " << fa << endl;
res += cnt[0] * cnt[0];
res += cnt[2] * cnt[1] * 2;
/*rep(i,0,2) cout << cnt[i] << " ";
cout << endl;*/
return res;
}
void dfz(int u,int fa){
vis[u] = 1;
ans += calc(u,fa,0);
for(auto i:e[u]){
int v = i.v, w = i.w;
if(vis[v] || v == fa) continue;
ans -= calc(v,u,w);
root = 0,mx[0] = INT_MAX,S = sz[v];
get_root(v,u);
get_root(root,-1);
dfz(root,-1);
}
}
int main()
{
IOS
cin >> n;
rep(i,2,n){
int u,v,w;
cin >> u >> v >> w;
e[u].push_back({v,w});
e[v].push_back({u,w});
}
S = n,root = 0,mx[0] = INT_MAX;
get_root(1,-1);
get_root(root,-1);
dfz(root,-1);
ll ans2 = n * n;
ll tmp = __gcd(ans,ans2);
cout << ans/tmp << "/" << ans2/tmp;
return 0;
}
/*
5
1 2 1
1 3 2
1 4 1
2 5 3
*/