题目大意
给出一颗树。
求
∑n−1i=1∑nj=i+1(a[i] xor a[j])∗dis(i,j)
dis(i,j)表示i到j的最短路。
点剖
这不用说了,拆位,然后点剖。
因为是有序对其实我们可以搞成无序对然后答案除以2。
#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const int maxn=30000+10,maxd=18;
int a[maxn],b[maxn],size[maxn],d[maxn][maxd+10],belong[maxn][maxd+10],co[maxn][maxd+10],two[maxd+10];
ll sum[maxn][maxd+10][2][2],num[maxn][maxd+10][2][2];
bool bz[maxn];
int h[maxn],go[maxn*2],dis[maxn*2],next[maxn*2];
int i,j,k,l,t,n,m,tot,top,cnt;
ll ans;
void add(int x,int y,int z){
go[++tot]=y;
dis[tot]=z;
next[tot]=h[x];
h[x]=tot;
}
void travel(int x,int y){
a[++top]=x;
size[x]=1;
int t=h[x];
while (t){
if (go[t]!=y&&!bz[go[t]]){
travel(go[t],x);
size[x]+=size[go[t]];
}
t=next[t];
}
}
void dfs(int x,int y,int z,int u){
belong[x][z]=u;
int t=h[x];
while (t){
if (go[t]!=y&&!bz[go[t]]){
d[go[t]][z]=d[x][z]+dis[t];
dfs(go[t],x,z,u);
}
t=next[t];
}
}
void dg(int x,int y,int z,int u){
co[x][z]=u;
int t=h[x];
while (t){
if (go[t]!=y&&!bz[go[t]]) dg(go[t],x,z,u);
t=next[t];
}
}
void count(int x,int y,int f,int haofan){
int i;
fo(i,0,maxd){
ans+=(ll)(sum[belong[x][y]][i][1-(b[x]/two[i])%2][0]-num[co[x][y]][i][1-(b[x]/two[i])%2][0])*two[i]*f;
ans+=(ll)d[x][y]*(sum[belong[x][y]][i][1-(b[x]/two[i])%2][1]-num[co[x][y]][i][1-(b[x]/two[i])%2][1])*two[i]*f;
}
}
void solve(int x,int y){
top=0;
travel(x,0);
int j=x,k=0,t;
while (1){
t=h[j];
while (t){
if (go[t]!=k&&!bz[go[t]]&&size[go[t]]>top/2){
k=j;
j=go[t];
break;
}
t=next[t];
}
if (!t) break;
}
d[j][y]=0;
dfs(j,0,y,j);
t=h[j];
while (t){
if (!bz[go[t]]) dg(go[t],j,y,++cnt);
t=next[t];
}
fo(i,1,top)
fo(k,0,maxd){
sum[belong[a[i]][y]][k][(b[a[i]]/two[k])%2][0]+=(ll)d[a[i]][y];
sum[belong[a[i]][y]][k][(b[a[i]]/two[k])%2][1]++;
num[co[a[i]][y]][k][(b[a[i]]/two[k])%2][0]+=(ll)d[a[i]][y];
num[co[a[i]][y]][k][(b[a[i]]/two[k])%2][1]++;
}
fo(i,1,top) count(a[i],y,1,0);
bz[j]=1;
t=h[j];
while (t){
if (!bz[go[t]]) solve(go[t],y+1);
t=next[t];
}
}
int main(){
freopen("tree.in","r",stdin);freopen("tree.out","w",stdout);
two[0]=1;
fo(i,1,maxd) two[i]=two[i-1]*2;
scanf("%d",&n);
fo(i,1,n) scanf("%d",&b[i]);
fo(i,1,n-1){
scanf("%d%d%d",&j,&k,&l);
add(j,k,l);add(k,j,l);
}
scanf("%d",&m);
if (m){
scanf("%d%d",&j,&k);
b[j]=k;
m--;
}
else{
fclose(stdin);fclose(stdout);
return 0;
}
solve(1,0);
printf("%lld\n",ans/2);
while (m--){
scanf("%d%d",&j,&k);
fo(i,0,maxd){
count(j,i,-2,0);
fo(l,0,maxd){
sum[belong[j][i]][l][(b[j]/two[l])%2][0]-=(ll)d[j][i];
sum[belong[j][i]][l][(b[j]/two[l])%2][1]--;
num[co[j][i]][l][(b[j]/two[l])%2][0]-=(ll)d[j][i];
num[co[j][i]][l][(b[j]/two[l])%2][1]--;
}
if (belong[j][i]==j) break;
}
b[j]=k;
fo(i,0,maxd){
fo(l,0,maxd){
sum[belong[j][i]][l][(b[j]/two[l])%2][0]+=(ll)d[j][i];
sum[belong[j][i]][l][(b[j]/two[l])%2][1]++;
num[co[j][i]][l][(b[j]/two[l])%2][0]+=(ll)d[j][i];
num[co[j][i]][l][(b[j]/two[l])%2][1]++;
}
count(j,i,2,0);
if (belong[j][i]==j) break;
}
printf("%lld\n",ans/2);
}
fclose(stdin);fclose(stdout);
}