又是 ix35 神仙出的题,先以 mol 为敬 %%%
首先预处理出根节点到每个点路径上权值的异或和 \(dis_i\),那么两点 \(a,b\) 路径上权值的异或和显然为 \(dis_a\oplus dis_b\)。
我们考虑探究 \(a,b\) 与 \(c,d\) 间的路径不相交意味着什么。记 \(l=lca(a,b)\),显然 \(c,d\) 不能一个在 \(l\) 子树内,一个在 \(l\) 子树外,否则它们间的路径就会经过 \(l\) 了。那么分两种情况,\(c,d\) 全在 \(l\) 子树外,和 \(c,d\) 全在 \(l\) 子树内。\(c,d\) 全在子树外的情况显然好搞定,只要 \(c,d\) 都在 \(l\) 的子树外,那么 \(a,b\) 与 \(c,d\) 之间的路径就肯定不会相交。比较麻烦的是 \(c,d\) 全在 \(l\) 子树内的情况,记 \(l'=lca(c,d)\),显然 \(l'\neq l\),而 \(c,d\) 都在 \(l\) 子树内,故 \(l'\) 也在 \(l\) 子树内,如果我们交换 \((a,b)\) 和 \((c,d)\),那么可得 \(c,d\) 的 lca 在 \(a,b\) 的 lca \(l'\) 的子树外,故第二种情况可以规约到第一种情况。所以我们只用考虑第一种情况就行了。
考虑枚举 \(a,b\) 的 lca \(l\),如果我们按照 DFS 序将原树展开成一个序列,那么相当于在 \([dfn_l,dfn_l+sz_l-1]\) 和 \([1,dfn_l-1]\cup[dfn_l+sz_l,n]\) 中分别选择两个数 \(a,b\) 和 \(c,d\) 使得 \(dis_a\oplus dis_b+dis_c\oplus dis_d\) 最大。那么我们只用让它们分别最大即可。而如果我们令 \(dfn_i=dfn_{i-n}(i>n)\),那么后面那个区间并又可写成 \([dfn_l+sz_l,dfn_l+n-1]\)。于是现在题目转化为:给定一个序列 \(a\),要求在 \([l,r]\) 中选择两个数 \(a_i,a_j\),\(a_i\oplus a_j\) 的最大值。首先可以肯定的是这东西没法用 DS 直接维护,而本题 3e4 的数据范围也在疯狂暗示本题的根号算法。故考虑莫队,建立一个 01-trie,插入某个数 \(x\) 的时候就按照套路将其插入 01-trie,而本题的答案以取 \(\max\) 出现的,不支持删除。故使用回滚莫队,扫到右端点的时候记录一个 \(tmp\) 保存答案,解决一个询问之后就用临时保存的值还原答案即可。
时间复杂度 \(n\sqrt{n}\log w\)
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fz(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define ffe(it,v) for(__typeof(v.begin()) it=v.begin();it!=v.end();it++)
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,63,sizeof(a))
#define pb push_back
#define ppb pop_back
#define mp make_pair
template<typename T1,typename T2> void chkmin(T1 &x,T2 y){if(x>y) x=y;}
template<typename T1,typename T2> void chkmax(T1 &x,T2 y){if(x<y) x=y;}
typedef pair<int,int> pii;
typedef long long ll;
template<typename T> void read(T &x){
x=0;char c=getchar();T neg=1;
while(!isdigit(c)){if(c=='-') neg=-1;c=getchar();}
while(isdigit(c)) x=x*10+c-'0',c=getchar();
x*=neg;
}
const int MAXN=3e4;
const int SQRT=245;
const int LOG_N=30;
const int MAXP=1e6;
int n,hd[MAXN+5],to[MAXN*2+5],nxt[MAXN*2+5],cst[MAXN*2+5],ec=0;
void adde(int u,int v,int w){to[++ec]=v;cst[ec]=w;nxt[ec]=hd[u];hd[u]=ec;}
int dis[MAXN+5],dfn[MAXN+5],ed[MAXN+5],id[MAXN+5],tim=0;
void dfs(int x,int f){
dfn[x]=++tim;id[tim]=x;
for(int e=hd[x];e;e=nxt[e]){
int y=to[e],z=cst[e];if(y==f) continue;
dis[y]=dis[x]^z;dfs(y,x);
} ed[x]=tim;
}
int blk_sz,blk_cnt,L[SQRT+5],R[SQRT+5],bel[MAXN*2+5];
int w[MAXN*2+5];
struct query{
int l,r,id;
bool operator <(const query &rhs){
if(bel[l]!=bel[rhs.l]) return l<rhs.l;
return r<rhs.r;
}
} q[MAXN*2+5];
int ch[MAXP+5][2],siz[MAXP+5],ncnt=0;
void insert(int x,int v){
int cur=0;
for(int i=LOG_N;~i;i--){
int d=x>>i&1;
if(!ch[cur][d]) ch[cur][d]=++ncnt;
cur=ch[cur][d];siz[cur]+=v;
}
}
int query(int v){
int x=0,cur=0;
for(int i=LOG_N;~i;i--){
int d=v>>i&1;
if(siz[ch[cur][d^1]]) x|=1<<i,cur=ch[cur][d^1];
else cur=ch[cur][d];
} return x;
}
int ans=0,res[MAXN+5];
int main(){
scanf("%d",&n);
for(int i=1;i<n;i++){
int u,v,w;scanf("%d%d%d",&u,&v,&w);
adde(u,v,w);adde(v,u,w);
} dfs(1,0);
for(int i=1;i<=n;i++) w[i]=dis[id[i]];
for(int i=n+1;i<=n*2;i++) w[i]=w[i-n];
// for(int i=1;i<=n*2;i++) printf("%d\n",w[i]);
blk_sz=(int)sqrt(2*n);blk_cnt=(2*n-1)/blk_sz+1;
for(int i=1;i<=blk_cnt;i++){
L[i]=(i-1)*blk_sz+1;
R[i]=min(i*blk_sz,2*n);
for(int j=L[i];j<=R[i];j++) bel[j]=i;
}
for(int i=2;i<=n;i++){
q[i-1].l=dfn[i];q[i-1].r=ed[i];q[i-1].id=i;
q[i+n-2].l=ed[i]+1;q[i+n-2].r=dfn[i]+n-1;q[i+n-2].id=i;
// printf("%d %d %d\n",dfn[i],ed[i],i);
// printf("%d %d %d\n",ed[i]+1,dfn[i]+n-1,i);
} sort(q+1,q+(n<<1)-1);int cl=1,cr=0;
// for(int i=1;i<=(n<<1)-2;i++) printf("%d %d %d\n",q[i].l,q[i].r,q[i].id);
for(int i=1;i<=(n<<1)-2;i++){
if(i==1||bel[q[i].l]!=bel[q[i-1].l]){
cl=R[bel[q[i].l]]+1;cr=cl-1;
memset(siz,0,sizeof(siz));memset(ch,0,sizeof(ch));
ncnt=0;ans=0;
}
if(bel[q[i].l]==bel[q[i].r]){
int mx=-0x3f3f3f3f;
for(int j=q[i].l;j<=q[i].r;j++) insert(w[j],1);
for(int j=q[i].l;j<=q[i].r;j++) mx=max(mx,query(w[j]));
for(int j=q[i].l;j<=q[i].r;j++) insert(w[j],-1);
res[q[i].id]+=mx;continue;
}
while(cr<q[i].r) insert(w[++cr],1),ans=max(ans,query(w[cr]));
int tmp=ans;
while(cl>q[i].l) insert(w[--cl],1),ans=max(ans,query(w[cl]));
res[q[i].id]+=ans;
while(cl<R[bel[q[i].l]]+1) insert(w[cl++],-1);
ans=tmp;
} int mx=0;
for(int i=1;i<=n;i++) chkmax(mx,res[i]);
printf("%d\n",mx);
return 0;
}