[关闭]
@ysner 2018-10-15T20:06:04.000000Z 字数 2128 阅读 1698

一道不知名的题目

Trie 可持久化Trie 启发式合并 最小生成树 线段树合并


题面

有一棵大小为的带边权、点权的树,问有多少点对满足:
点权异或和树上简单路径的最大边权。

解析

这个最大边权显然不是暴力求出来的,因为要求给出两个点,复杂度
所以我们要枚举边权。

一开始可能会想到,从最大边开始,统计其两端子树之间的贡献,然后分治搞下去。
但这样其实很难保证复杂度。
换个方向思考,可以像做最小生成树一样,从小往大加边。
显然每加一条边,这条边就是两端联通块相互之间的最大边权

然后异或和显然可以弄棵树来搞。
这个树可以跟着并查集一起维护,每次合并并查集的同时把树也合并。
所以需要线段树合并可持久化
(注意如果一个一个点地合并树会!!!)

最后注意边界,时,新建结点再;而直接

  1. #include<iostream>
  2. #include<cmath>
  3. #include<cstdio>
  4. #include<cstdlib>
  5. #include<cstring>
  6. #include<algorithm>
  7. #define ll long long
  8. #define re register
  9. #define il inline
  10. #define fp(i,a,b) for(re int i=a;i<=b;++i)
  11. #define fq(i,a,b) for(re int i=a;i>=b;--i)
  12. using namespace std;
  13. const int N=2e5+100;
  14. int n,val[N],W,h[N],cnt,sz[N*32],da[N],t[2][N*32],f[N],rt[N],sta[N*32],top;
  15. ll ans;
  16. struct dat{int u,v,w;il bool operator < (const dat &o) const {return w<o.w;}}a[N];
  17. struct Edge{int to,nxt;}e[N<<1];
  18. il void add(re int u,re int v){e[++cnt]=(Edge){v,h[u]};h[u]=cnt;}
  19. il int find(re int x){return x==f[x]?x:f[x]=find(f[x]);}
  20. il ll gi()
  21. {
  22. re ll x=0,t=1;
  23. re char ch=getchar();
  24. while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
  25. if(ch=='-') t=-1,ch=getchar();
  26. while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
  27. return x*t;
  28. }
  29. il void Insert(re int &x,re int k,re int d)
  30. {
  31. if(!x) x=sta[top--];++sz[x];
  32. if(d<0) return;
  33. Insert(t[(k>>d)&1][x],k,d-1);
  34. }
  35. il int Query(re int x,re int k,re int w,re int d)
  36. {
  37. if(d<0) return 0;
  38. re int A=k>>d&1,B=w>>d&1,s=0;
  39. if(!B) s+=sz[t[A^1][x]];
  40. s+=Query(t[A^B][x],k,w,d-1);
  41. return s;
  42. }
  43. il void dfs1(re int u,re int fa,re int x,re int w)
  44. {
  45. ans+=Query(rt[x],val[u],w,29);
  46. for(re int i=h[u];i+1;i=e[i].nxt)
  47. {
  48. re int v=e[i].to;
  49. if(v==fa) continue;
  50. dfs1(v,u,x,w);
  51. }
  52. }
  53. il void clear(re int x)
  54. {
  55. if(!x) return;
  56. clear(t[0][x]);clear(t[1][x]);
  57. t[0][x]=t[1][x]=sz[x]=0;sta[++top]=x;
  58. }
  59. il int Merge(re int x,re int y)
  60. {
  61. if(x) sz[x]+=sz[y];
  62. if(!x||!y) return x+y;
  63. t[0][x]=Merge(t[0][x],t[0][y]);
  64. t[1][x]=Merge(t[1][x],t[1][y]);
  65. return x;
  66. }
  67. int main()
  68. {
  69. memset(h,-1,sizeof(h));
  70. fq(i,2e5*32,1) sta[++top]=i;
  71. n=gi();
  72. fp(i,1,n) val[i]=gi(),f[i]=i,da[i]=1,Insert(rt[i],val[i],29);
  73. fp(i,1,n-1) a[i].u=gi(),a[i].v=gi(),a[i].w=gi();
  74. sort(a+1,a+n);
  75. fp(i,1,n-1)
  76. {
  77. re int u=find(a[i].u),v=find(a[i].v);
  78. if(da[u]<da[v]) swap(u,v);
  79. dfs1(v,0,u,a[i].w);Merge(rt[u],rt[v]);
  80. f[v]=u;da[u]+=da[v];add(u,v);
  81. }
  82. printf("%lld\n",ans);
  83. return 0;
  84. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注