[TS-A1486][2013中国国家集训队第二次作业]树[树的重心,点分治]
首先考虑暴力,可以枚举每两个点求lca进行计算,复杂度O(n^3logn),再考虑如果枚举每个点作为lca去枚举这个点的子树中的点复杂度会大幅下降,如果我们将每个点递归考虑,每次计算过这个点就把这个点删掉,那么如果每次删掉的点是当前子树的重心,枚举点对的复杂度就只有O(logn),对于每次查询答案在trie树中找到时间复杂度基本可视为O(1),最后在分治同时考虑“关键点”即可。总复杂度O(nlogn)。
1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cstdlib> 5 #include <cstring> 6 #include <cmath> 7 #include <ctime> 8 9 using namespace std; 10 11 struct Edge 12 { 13 int to,next; 14 }e[210000]; 15 16 int n,k,Ans=-1; 17 int Size[110000],cnt,p[110000],f[110000],a[110000]; 18 bool visited[110000]; 19 20 void Add_edge(const int x,const int y) 21 { 22 e[++cnt].to=y; 23 e[cnt].next=p[x]; 24 p[x]=cnt; 25 return ; 26 } 27 28 struct Trie 29 { 30 private: 31 int c[110000][2]; 32 int d[3500000]; 33 int cnt,root; 34 35 public: 36 void insert(const int val,const int flag) 37 { 38 int pos=root,temp; 39 for(int i=30;i>=0;--i) 40 { 41 temp=!!(val&(1<<i)); 42 if(!c[pos][temp]) 43 { 44 c[pos][temp]=++cnt; 45 c[cnt][0]=c[cnt][1]=0; 46 d[cnt]=0; 47 } 48 d[pos]=max(d[pos],flag); 49 pos=c[pos][temp]; 50 } 51 d[pos]=max(d[pos],flag); 52 return ; 53 } 54 55 void query(const int val,const int flag) 56 { 57 int temp,num=0,pos=root; 58 for(int i=30;i>=0;--i) 59 { 60 temp=!(val&(1<<i)); 61 if(c[pos][temp] && d[c[pos][temp]]+flag>=k) 62 { 63 pos=c[pos][temp]; 64 num|=(1<<i); 65 } 66 else 67 { 68 if(!c[pos][temp^1] || d[c[pos][temp^1]]+flag<k) 69 { 70 num=-1; 71 break; 72 } 73 else pos=c[pos][temp^1]; 74 } 75 } 76 if(k<=flag)Ans=max(Ans,val); 77 Ans=max(Ans,num); 78 } 79 80 void clear() 81 { 82 root=1; 83 cnt=1; 84 c[root][0]=c[root][1]=0; 85 d[root]=0,d[0]=0; 86 return ; 87 } 88 }T; 89 90 int Dfs(const int S,const int fa) 91 { 92 Size[S]=1; 93 for(int i=p[S];i;i=e[i].next) 94 { 95 if(e[i].to!=fa && !visited[e[i].to]) 96 Size[S]+=Dfs(e[i].to,S); 97 } 98 return Size[S]; 99 } 100 101 void Get(const int S,const int fa,int & Centre,int & tot,const int nn) 102 { 103 int Max=0,i; 104 105 for(i=p[S];i;i=e[i].next) 106 { 107 if(e[i].to!=fa && !visited[e[i].to]) 108 { 109 Get(e[i].to,S,Centre,tot,nn); 110 Max=max(Max,Size[e[i].to]); 111 } 112 } 113 Max=max(Max,nn-Size[S]); 114 if(tot>Max)tot=Max,Centre=S; 115 return ; 116 } 117 118 void Query(const int S,const int fa,int A,int F) 119 { 120 A^=a[S];F+=f[S]; 121 T.query(A,F); 122 for(int i=p[S];i;i=e[i].next) 123 { 124 if(e[i].to!=fa && !visited[e[i].to]) 125 Query(e[i].to,S,A,F); 126 } 127 return ; 128 } 129 130 void Insert(const int S,const int fa,int A,int F) 131 { 132 A^=a[S];F+=f[S]; 133 T.insert(A,F); 134 for(int i=p[S];i;i=e[i].next) 135 { 136 if(e[i].to!=fa && !visited[e[i].to]) 137 Insert(e[i].to,S,A,F); 138 } 139 return ; 140 } 141 142 void TDC(const int S) 143 { 144 int i,Centre; 145 146 visited[S]=true; 147 for(i=p[S];i;i=e[i].next) 148 { 149 if(!visited[e[i].to]) 150 { 151 int tot=n+1; 152 Dfs(e[i].to,0); 153 Get(e[i].to,0,Centre,tot,Size[e[i].to]); 154 TDC(Centre); 155 } 156 } 157 T.clear(); 158 for(i=p[S];i;i=e[i].next) 159 { 160 if(!visited[e[i].to]) 161 { 162 Query(e[i].to,0,a[S],f[S]); 163 Insert(e[i].to,0,0,0); 164 } 165 } 166 T.query(a[S],f[S]); 167 visited[S]=false; 168 return ; 169 } 170 171 int main() 172 { 173 int i,x,y; 174 175 scanf("%d%d",&n,&k); 176 for(i=1;i<=n;++i)scanf("%d",&f[i]); 177 for(i=1;i<=n;++i)scanf("%d",&a[i]); 178 179 for(i=1;i<n;++i) 180 { 181 scanf("%d%d",&x,&y); 182 Add_edge(x,y); 183 Add_edge(y,x); 184 } 185 186 TDC(1); 187 188 printf("%d\n",Ans); 189 190 return 0; 191 }