hdu-5571 tree

来源:互联网 发布:it have 还是it has 编辑:程序博客网 时间:2024/05/18 15:30

题意:

给出一个n个结点的树,有点权a[x]和边权val(x,y);

现有m次修改某个点的点权;

求每次操作后它所有结点对(x,y)之间的(a[x] xor a[y])*dis(x,y);

其中dis(x,y)指两点间距离;

n<=30000,m<=30000;


题解:

感觉上周的BC好奇怪啊。。。A上来就高精度没模板打个卵,B题SB题;

写完AB感觉药丸于是果断去看D,仔细一看卧槽。。。于是颓了一个小时C没做出来跪了;

感觉这道题的思路还是挺显然的,然而动态点分治我真的码不出来啊QAQ;

虽说如此我也没看懂题解,最后还是orz wyfcyx大爷涨了个新姿势才会做的。。


首先异或这东西在这里没什么好用的性质,我们只能把它拆开看了;

拆成每一位之后问题转化成了树上每个点有黑白两种颜色,动态维护不同颜色点对的总距离(我觉得不动态我还是能写出来的)

动态维护点分治的话,我们考虑每个点分治子树内跨过根的答案;

比如我现在修改的点是x,那么跨过根到x的答案和就是x到根的长度*对面的不同色点个数+对面不同色点到根的距离和;

因为到这里的信息是可减的,于是维护这些信息就可以了:分治结构中两种颜色点个数,两种颜色到根的点距离和,两种颜色到根在分治结构中父亲的距离和;

注意后两个都要开long long;

然后每次修改将当前点的答案都减去,修改之后再加上就可以了;

时间复杂度是O((n+m)*logn*14);

我还是too naive,被D动态点分治做的少啦。。。(那我也不做)


代码:


#include<queue>#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#define N 31000#define M 14using namespace std;typedef long long ll;int nxt[N<<1],to[N<<1],val[N<<1],head[N],ce;int a[N],fa[N],deep[N],fv[N][16],rt;ll ans;bool ban[N];int in[N];queue<int>q;struct Tree{int size[N][2];ll f[N][2],g[N][2];ll calc(int x,bool col){ll ret=f[x][!col];for(int y=x;fa[y];y=fa[y])ret+=(ll)(size[fa[y]][!col]-size[y][!col])*(fv[x][deep[fa[y]]])+f[fa[y]][!col]-g[y][!col];return ret;}}tr[M];void init(){ce=0;ans=0;memset(head,0,sizeof(head));memset(ban,0,sizeof(ban));memset(fv,0,sizeof(fv));memset(tr,0,sizeof(tr));}void add(int x,int y,int v){to[++ce]=y;val[ce]=v;nxt[ce]=head[x];head[x]=ce;}int getG(int x,int pre,int &g,int n){int temp,ma,size,i;for(i=head[x],ma=0,size=1;i;i=nxt[i]){if(!ban[to[i]]&&to[i]!=pre){temp=getG(to[i],x,g,n);ma=max(temp,ma);size+=temp;}}ma=max(ma,n-size);if(ma<=n>>1)g=x;return size;}void dfs(int x,int pre,int dis,int dp){fv[x][dp]=dis;for(int i=head[x];i;i=nxt[i]){if(!ban[to[i]]&&to[i]!=pre){dfs(to[i],x,dis+val[i],dp);}}}void Build(int x,int n){ban[x]=1;if(n==1)return ;int temp,i,g;dfs(x,0,0,deep[x]);for(i=head[x];i;i=nxt[i]){if(!ban[to[i]]){temp=getG(to[i],0,g,0);getG(to[i],0,g,temp);deep[g]=deep[x]+1;fa[g]=x;Build(g,temp);}}}void update(int x,int y){int i,j,k;for(i=0;i<M;i++){ans-=(1ll<<i)*tr[i].calc(x,a[x]>>i&1);}for(i=0;i<M;i++)for(j=x;j;j=fa[j]){tr[i].size[j][a[x]>>i&1]--;tr[i].f[j][a[x]>>i&1]-=fv[x][deep[j]];tr[i].g[j][a[x]>>i&1]-=fv[x][deep[fa[j]]];}a[x]=y;for(i=0;i<M;i++)for(j=x;j;j=fa[j]){tr[i].size[j][a[x]>>i&1]++;tr[i].f[j][a[x]>>i&1]+=fv[x][deep[j]];tr[i].g[j][a[x]>>i&1]+=fv[x][deep[fa[j]]];}for(i=0;i<M;i++){ans+=(1ll<<i)*tr[i].calc(x,a[x]>>i&1);}}int main(){int n,m,i,j,k,x,y,v;while(scanf("%d",&n)!=EOF){init();for(i=1;i<=n;i++){scanf("%d",a+i);}for(i=1;i<n;i++){scanf("%d%d%d",&x,&y,&v);add(x,y,v);add(y,x,v);}getG(1,0,rt,n);deep[rt]=fa[rt]=0;Build(rt,n);for(i=1;i<=n;i++){in[fa[i]]++;for(j=0;j<M;j++){for(k=i;fa[k];k=fa[k]){tr[j].g[k][a[i]>>j&1]+=fv[i][deep[fa[k]]];}}}for(i=1;i<=n;i++)if(!in[i])q.push(i);while(!q.empty()){x=q.front(),q.pop();for(i=0;i<M;i++){tr[i].size[x][a[x]>>i&1]++;tr[i].size[fa[x]][0]+=tr[i].size[x][0];tr[i].size[fa[x]][1]+=tr[i].size[x][1];tr[i].f[fa[x]][0]+=tr[i].g[x][0];tr[i].f[fa[x]][1]+=tr[i].g[x][1];}in[fa[x]]--;if(!in[fa[x]])q.push(fa[x]);}for(i=1;i<=n;i++){for(j=0;j<M;j++){ans+=(1ll<<j)*tr[j].calc(i,a[i]>>j&1);}}ans>>=1;scanf("%d",&m);for(i=1;i<=m;i++){scanf("%d%d",&x,&y);update(x,y);cout<<ans<<endl;}}return 0;}



0 0
原创粉丝点击