BZOJ 1468 Tree(点分治+双指针 模板题)

Description

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

Input

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

Output

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

Sample Input

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

Sample Output

5

Hint

Source

LTC男人八题系列

题解:模板题,点分治+双指针

#include <bits/stdc++.h>
#define IO_read ios::sync_with_stdio(false);cin.tie(0)
#define fre freopen("in.txt", "r", stdin)
#define _for(i,a,b) for(int i=a; i< b; i++)
#define _rep(i,a,b) for(int i=a; i<=b; i++)
#define inf 0x3f3f3f3f
#define lowbit(a) ((a)&-(a))
using namespace std;
typedef long long ll;
template <class T>
void read(T &x)
{
    char c; bool op=0;
    while(c=getchar(), c<'0'||c>'9') if(c=='-') op=1;
    x=c-'0';
    while(c=getchar(), c>='0'&&c<='9') x=x*10+c-'0';
    if(op) x=-x;
}
template <class T>
void write(T x)
{
    if(x<0) putchar('-'), x=-x;
    if(x>=10) write(x/10);
    putchar('0'+x%10);
}

const int maxn=5e4+5;
int head[maxn], tot;
struct Edge{
    int to, next, val;
}edge[maxn*2];

void addedge(int u, int v, int w)
{
    edge[++tot]={v, head[u], w};
    head[u]=tot;
}

int n, k;
ll ans;
int sz[maxn], vis[maxn], max_son, rt, Size;
ll dis[maxn], q[maxn];
int l, r;

void get_rt(int u, int fa)
{
    sz[u]=1;
    int num=0;
    for(int i=head[u]; i!=-1; i=edge[i].next)
    {
        int v=edge[i].to;
        if(vis[v] || v==fa) continue;
        get_rt(v, u);
        sz[u]+=sz[v];
        num=max(num, sz[v]);
    }
    num=max(num, Size-sz[u]);
    if(num<max_son) max_son=num, rt=u;
}

void get_dis(int u, int fa)
{
    q[++r]=dis[u];
    for(int i=head[u]; i!=-1; i=edge[i].next)
    {
        int v=edge[i].to, w=edge[i].val;
        if(vis[v] || v==fa) continue;
        dis[v]=dis[u]+w;
        get_dis(v, u);
    }
}

ll solve(int u, int val)
{
    l=1, r=0, dis[u]=val;
    get_dis(u, 0);
    ll res=0;
    sort(q+1, q+r+1);
    while(l<r)  //双指针
    {
        if(q[l]+q[r]<=k) res+=r-l, ++l;
        else --r;
    }
    return res;
}

void divide(int u)
{
    ans+=solve(u, 0);
    vis[u]=true;
    for(int i=head[u]; i!=-1; i=edge[i].next)
    {
        int v=edge[i].to, w=edge[i].val;
        if(vis[v]) continue;
        ans-=solve(v, w);  //容斥
        Size=sz[v], max_son=inf;
        get_rt(v, 0);
        divide(rt);
    }
}

int main()
{
    IO_read;
    //fre;
    cin>>n;
    memset(head, -1, sizeof(head));
    for(int i=1,u,v,w; i<n; i++)
    {
        cin>>u>>v>>w;
        addedge(u, v, w), addedge(v, u, w);
    }
    cin>>k;
    Size=n, max_son=inf;
    get_rt(1, 0);
    divide(rt);
    cout<<ans<<"
";
}
原文地址:https://www.cnblogs.com/Yokel062/p/11749245.html