AT3913 XOR Tree
题面传送门
考虑其实这种路径修改的东西不是很好搞,所以考虑差分。
另一个点的权值为与他相邻的所有边的权值,那么发现一条路径修改只会改变两个端点的权值。
然后就和这个树没有半毛钱关系了,变成了有\(n\)个树每次找两个点都异或一个值。
首先可以贪心,如果有两个点一样那么可以直接干掉。
然后就剩下不超过\(15\)个数,直接状压dp就好了。
时间复杂度\(O(n+3^{15})\)
code:
#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define ll long long
#define db double
#define lb long db
#define N (100000+5)
#define M ((1<<16)+5)
#define K (1000+5)
#define mod 998244353
#define Mod (mod-1)
#define eps (1e-9)
#define ull unsigned ll
#define it iterator
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) (n*(x-1)+(y))
#define R(n) (rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using namespace std;
int n,m=(1<<15),k,x,y,z,Ns,Q[N],dp[M],Fl[N],Ans,G[N],cnt,N1,N2;
struct Edge{int to,w;};vector<Edge> S[N];
I void dfs(int x,int La){for(Edge d:S[x]) Q[x]^=d.w;Fl[Q[x]]++;for(Edge d:S[x]) d.to^La&&(dfs(d.to,x),0);}
int main(){
freopen("1.in","r",stdin);
int i,j;scanf("%d",&n);for(i=1;i<n;i++) scanf("%d%d%d",&x,&y,&z),S[x].PB((Edge){y,z}),S[y].PB((Edge){x,z});dfs(0,-1);
for(i=1;i<=15;i++) Ans+=Fl[i]/2,Fl[i]&=1,Fl[i]&&(Ns^=(1<<i-1));Me(dp,0x3f);dp[0]=0;for(i=1;i<m;i++){
if((Ns&i)^i) continue;N1=N2=0;for(j=1;j<=15;j++) if(i>>(j-1)&1) N1^=j,N2++;if(N1) continue;dp[i]=N2-1;
for(j=(i-1)&i;j;j=(j-1)&i) dp[i]=min(dp[i],dp[j]+dp[i^j]);
}printf("%d\n",Ans+dp[Ns]);
}