您的位置:首页 > 其它

【JZOJ 4503】 异或树 动态点分治

2016-06-12 20:13 288 查看

Description



这只熊孩子会搞T次破坏,点权为Ei。

对于100%的数据2<=n,T<=30000,Ei<=16384

Analysis

Ei<=16384=214,这启示了我们什么?

xor怎么解决?可以拆位做,最后每个二进制位合并。

这题如果不搞破坏,点分治可做。

可是搞破坏,难道要打动态点分治?

没错!

首先把修改操作拆成位数个,对于该位0改成1,就加上0的点的权值减去1的点的权值。

但是怎么算任意点到该点的权值和?

把我们上面点分治的分治树copy下来,每次往父节点跳,对于当前点,算出它的兄弟点到它的权值和。当然最开始要算上它的子树到它的权值和。因为分治树的深度是log2n的,所以单次询问的复杂度是O(log2n)的。

一个小细节,分治树上的父子关系可能与原树上的不同,所以两点间距离要用原树上dis[u]+dis[v]-2*dis[lca]来解决。HowarLi貌似有一种高级的方法不用lca。

具体实现繁(wei)琐(suo),若有做此题的欲望应做好心理准备(本蒟蒻被虐了一周)。

Code

代码比较长。而且垫底了,so sad

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,b,a) for(int i=b;i>=a;i--)
#define efo(i,u) for(int i=last[u];i;i=next[i])
using namespace std;
typedef long long ll;
const int N=30010,M=N*2;
int n,m,tot,val,num,rt,root,to[M],next[M],wei[M],last
;
int f
[16],dep
,dis
,fa
,size
,sum
[2];
ll ans,a
;
struct node
{
ll dis,s,a,id;
}b
,c
;
struct lyd
{
ll s0,n0,fs;
}sm
[15][2];
bool bz
;
void link(int u,int v,int w)
{
to[++tot]=v,wei[tot]=w,next[tot]=last[u],last[u]=tot;
}
void dfs1(int v,int from,int d,int k)
{
f[v][0]=from,dep[v]=d,dis[v]=k;
efo(i,v)
{
int u=to[i];
if(u==from) continue;
dfs1(u,v,d+1,k+wei[i]);
}
}
int lca(int u,int v)
{
if(dep[u]<dep[v]) swap(u,v);
fd(i,int(log2(dep[u])),0)
if(dep[f[u][i]]>=dep[v]) u=f[u][i];
fd(i,int(log2(dep[u])),0)
if(f[u][i]!=f[v][i]) u=f[u][i],v=f[v][i];
if(u!=v) return f[u][0];
return u;
}
ll dist(int x,int y)
{
return dis[x]+dis[y]-2*dis[lca(x,y)];
}
void getrt(int v,int from,int num)
{
size[v]=1;
int x=0;
efo(i,v)
{
int u=to[i];
if(u==from || bz[u]) continue;
getrt(u,v,num);
x=max(x,size[u]);
size[v]+=size[u];
}
int mx=max(x,num-size[v]);
if(mx<val) val=mx,rt=v;
}
void dfs(int v,int from,int S,int k)
{
b[++m].s=S,b[m].dis=k,b[m].a=a[v],b[m].id=v;
efo(i,v)
{
int u=to[i];
if(u==from || bz[u]) continue;
dfs(u,v,S,k+wei[i]);
}
}
void divide(int v,int from,int num)
{
val=2147483647;
getrt(v,from,num);
fa[rt]=from;
if(!root) root=rt,fa[root]=root;
int rt1=rt;
m=0;
efo(i,rt)
{
int u=to[i];
if(u==from || bz[u]) continue;
dfs(u,rt,u,wei[i]);
}
fo(i,1,m) ans+=(b[i].a^a[rt])*b[i].dis;
fo(j,0,14)
{
int c1=0;
ll s0=0,n0=0,t=0;
sm[rt][j][(a[rt]&(1<<j))>=1].n0=1;
sm[rt][j][(a[rt]&(1<<j))>=1].fs+=dist(rt,fa[rt]);
fo(i,1,m)
{
bool p=(b[i].a&(1<<j))>=1;
sm[rt][j][p].n0++,sm[rt][j][p].s0+=b[i].dis;
sm[rt][j][p].fs+=dist(fa[rt],b[i].id);
if(p) c[++c1]=b[i];
else
{
s0+=b[i].dis,n0++;
sum[b[i].s][0]+=b[i].dis,sum[b[i].s][1]++;
}
}
fo(i,1,c1) t+=c[i].dis*(n0-sum[c[i].s][1])+s0-sum[c[i].s][0];
fo(i,1,m) sum[b[i].s][0]=sum[b[i].s][1]=0;
ans+=t*(1<<j);
}
bz[rt]=1;
efo(i,rt1)
{
int u=to[i];
if(u==from || bz[u]) continue;
divide(u,rt1,size[u]);
}
}
ll change(int v,int x,bool bz)
{
ll t=sm[v][x][bz].s0-sm[v][x][1-bz].s0,s0,n0,len;
for(int u=v;;u=fa[u])
{
if(u==root) break;
len=dist(v,fa[u]);
s0=sm[fa[u]][x][bz].s0-sm[u][x][bz].fs;
n0=sm[fa[u]][x][bz].n0-sm[u][x][bz].n0;
t+=s0+n0*len;
s0=sm[fa[u]][x][1-bz].s0-sm[u][x][1-bz].fs;
n0=sm[fa[u]][x][1-bz].n0-sm[u][x][1-bz].n0;
t-=s0+n0*len;
}
for(int u=v;;u=fa[u])
{
sm[u][x][1-bz].n0++,sm[u][x][bz].n0--;
if(u==root) break;
len=dist(v,fa[u]);
sm[u][x][1-bz].fs+=len,sm[u][x][bz].fs-=len;
sm[fa[u]][x][1-bz].s0+=len,sm[fa[u]][x][bz].s0-=len;
}
return t;
}
int main()
{
int _,u,v,w;
scanf("%d",&n);
fo(i,1,n) scanf("%d",&a[i]);
fo(i,1,n-1)
{
scanf("%d %d %d",&u,&v,&w);
link(u,v,w),link(v,u,w);
}
dfs1(1,1,1,0);
fo(j,1,int(log2(n)))
fo(i,1,n) f[i][j]=f[f[i][j-1]][j-1];
divide(1,0,n);
scanf("%d",&_);
while(_--)
{
scanf("%d %d",&v,&w);
fo(i,0,14)
if((a[v]^w)&(1<<i)) ans+=(1<<i)*change(v,i,a[v]&(1<<i));
a[v]=w;
printf("%lld\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: