HDU5314 Happy King

来源:互联网 发布:龙神契约披风升阶数据 编辑:程序博客网 时间:2024/05/26 22:05



题意:

给定一颗树,每个点有点权,求有多少个点对(u,v)满足u到v的路径中点权最大值与最小值之差不大于D

被题意杀了一天......

一开始以为(u,v)和(v,u)算一种,(u,u)也算一种方案,样例过了结果wa了一天。实际上是前者算两种后者不算



题解:

应该是一个很裸的点分治+二维偏序吧

统计答案是记录分治中心到每个点的最大最小值,然后相当于对于每个点(mini,maxi)统计有多少个点对j满足(minj >= mini , maxj<=mini+d , minj >=maxi-d)

离线一下,关于min从大到小排序树状数组弄弄就好了

感觉点分治,二维偏序,离散化这三个算法都不是很熟。就当贴个模板吧

#pragma GCC optimize(3)#pragma comment(linker, "/STACK:102400000,102400000")#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#define LL long longusing namespace std;const int N=1e5+10;const int inf=0x3f3f3f3f;int T,n,d,num,cnt,tot,dif,root,maxsize;int v[N<<1],val[N],use[N],siz[N],fir[N],arr[N<<1],nex[N<<1],tree[N<<1];pair<int,int> pnt[N];LL ans;bool cmp(pair<int,int> &x,pair<int,int> &y) {if (x.first!=y.first) return x.first>y.first;return x.second>y.second;}inline void read(int &x) {x=0; register char c=getchar();while (c>'9'||c<'0') c=getchar();while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();}inline void Add_Edge(int x,int y) {nex[++cnt]=fir[x];fir[x]=cnt;arr[cnt]=y;}inline int GetNum(int x) {if (x<v[1]) return 0;return lower_bound(v+1,v+dif+1,x+1)-v-1;}inline void Updata(int x,int del) {for (;x<=dif;x+=x&-x) tree[x]+=del;}inline int Query(int x) {register int ans=0;for (;x;x-=x&-x) ans+=tree[x];return ans;}inline void FindRoot(int x,int fa) {siz[x]=1; int ms=0;for (int i=fir[x];i;i=nex[i])if (!use[arr[i]]&&arr[i]!=fa) {FindRoot(arr[i],x);siz[x]+=siz[arr[i]];ms=max(ms,siz[arr[i]]);}if (max(ms,tot-siz[x])<maxsize) {maxsize=max(ms,tot-ms);root=x;}}inline void dfs(int x,int fa,int minx,int maxx) {minx=min(minx,val[x]);maxx=max(maxx,val[x]);pnt[++num]=make_pair(minx,maxx);for (int i=fir[x];i;i=nex[i])if (arr[i]!=fa&&!use[arr[i]])dfs(arr[i],x,minx,maxx);}inline void Disperse() {for (int i=1;i<=num;i++) {v[++dif]=pnt[i].first;v[++dif]=pnt[i].second;}sort(v+1,v+dif+1);dif=unique(v+1,v+dif+1)-v-1;}inline LL Calc(int x,int cost) {num=0; dif=0;if (~cost) dfs(x,0,cost,cost);else dfs(x,0,inf,0);sort(pnt+1,pnt+num+1,cmp);Disperse();LL ax=0;memset(tree,0,sizeof(int)*(dif+5));for (int i=1;i<=num;i++) if (pnt[i].second-pnt[i].first<=d) {int t;t=GetNum(pnt[i].first+d);ax+=Query(t);t=GetNum(pnt[i].second-d-1);if (t>0) ax-=Query(t);t=GetNum(pnt[i].second);Updata(t,1);}return ax<<1;}inline void Solve(int x) {use[x]=1;ans+=Calc(x,-1);   for (int i=fir[x];i;i=nex[i]) {if (!use[arr[i]]) {tot=siz[arr[i]];ans-=Calc(arr[i],val[x]);maxsize=inf;FindRoot(arr[i],x);Solve(root);}}}inline void Work() {cnt=0;read(n); read(d);memset(use,0,sizeof(int)*(n+5));memset(fir,0,sizeof(int)*(n+5));for (int i=1;i<=n;i++) read(val[i]),val[i]++;for (int i=1;i<n;i++) {int u,v;read(u); read(v);Add_Edge(u,v); Add_Edge(v,u);}tot=n; maxsize=inf;FindRoot(1,0);ans=0;Solve(root);printf("%lld\n",ans);memset(tree,0,sizeof(int)*(n+5));n=d=num=cnt=tot=dif=root=maxsize=0;}signed main() {read(T);while (T--) Work();return 0;}


原创粉丝点击