ICPC 2019 Hong Kong C(点分治)
90nwyn
2020-10-03 17:32:11
[题目链接](https://vjudge.net/problem/Gym-102452C)
------------
对于树上的一条简单路径$<x,y>$,路径上的权值和为$sum$,路径上权值最大值为$mx$
能够构成多边形的充要条件为$sum-mx>mx$,即$sum>2 *mx$
考虑点分治
令$sum_{i}$为点 $i$ 到树的重心$t$的路径权值和,$mx_i$为路径上权值最大值,$a_t$为重心的权值
那么经过重心$t$且满足条件的路径$<x,y>$满足:$sum_x+sum_y-a_t>2*max(mx_x,mx_y)$
对当前要处理的所有点按$mx_i$从小到大排序,然后通过二分$+$树状数组计算
------------
```cpp
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int M=2e5+5;
int n,a[M],siz[M],mxsiz[M],rt,rtsiz,vis[M],c[M],m;
ll ans;
vector< pair<int,ll> > v;
vector<ll> s;
vector<int> vt[M];
void getroot(int x,int fa)
{
siz[x]=1;
mxsiz[x]=0;
for(auto y:vt[x])
{
if(vis[y]||y==fa)continue;
getroot(y,x);
siz[x]+=siz[y];
mxsiz[x]=max(mxsiz[x],siz[y]);
}
mxsiz[x]=max(mxsiz[x],rtsiz-mxsiz[x]);
if(mxsiz[x]<mxsiz[rt])rt=x;
}
void getval(int x,int fa,int mx,ll sum)
{
v.push_back(make_pair(mx,sum));
for(auto y:vt[x])
{
if(y==fa||vis[y])continue;
getval(y,x,max(mx,a[y]),sum+a[y]);
}
}
int lowbit(int x) {return x&(-x);}
void upd(int pos,int x){for(int i=pos;i<=m;i+=lowbit(i))c[i]+=x;}
int que(int pos){int res=0;for(int i=pos;i;i-=lowbit(i))res+=c[i];return res;}
ll calc(int x,ll d)
{
v.clear();s.clear();
getval(x,0,max(a[x],(int)d),d+a[x]);
sort(v.begin(),v.end());
for(auto p:v)s.push_back(p.second);
sort(s.begin(),s.end());
s.erase(unique(s.begin(),s.end()),s.end());
m=s.size();
for(int i=1;i<=m;i++)c[i]=0;
d=(d?d:a[x]);
ll res=0;
int cnt=0;
for(auto p:v)
{
int pos=upper_bound(s.begin(),s.end(),2*p.first+d-p.second)-s.begin();
res+=cnt-que(pos);
int k=lower_bound(s.begin(),s.end(),p.second)-s.begin()+1;
upd(k,1);
cnt++;
}
return res;
}
void solve(int x)
{
vis[x]=1;
ans+=calc(x,0);
for(auto y:vt[x])
{
if(vis[y])continue;
ans-=calc(y,a[x]);
rt=0;
mxsiz[0]=rtsiz=siz[y];
getroot(y,x);
solve(rt);
}
}
int main()
{
int T;scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
ans=0;
for(int i=1;i<=n;i++)vis[i]=0,vt[i].clear();
for(int i=1;i<=n-1;i++)
{
int x,y;scanf("%d%d",&x,&y);
vt[x].push_back(y);
vt[y].push_back(x);
}
rt=0;
mxsiz[0]=rtsiz=n;
getroot(1,0);
solve(rt);
printf("%lld\n",ans);
}
return 0;
}
```