• bzoj3730:震波


    题意:给一棵树,只有点权无边权, ,每次询问求以一个点为中心,半径为k的全职和。

    考虑动态树分治。我们对于每个点(点分树)维护两个树状数组。两个树状数组都以距离为下标,权值为内容。第一个树状数组维护子树中距离该点为k的权值和,第二个维护距离该点父亲距离为k的权值和。这样改权值时我们暴力爬树高,loglog复杂度(log的树高加上log的树状数组)。查询的时候一样爬树高,要注意容斥(把当前子树k的先加起来,往祖先上爬,如果距离小于k,假设为d,我们到祖先上去求一个k-d,再容斥掉原来这棵子树里被计算过的,这就是第二个树状数组的用处)。

    时间复杂度0(nloglog),空间复杂度O(nlog)(如果用线段树还要加一个log。这里BB一句,为什么树状数组不会爆呢,因为你每一层开的大小为子树大小的话,每层总和n,总共log层,空间就是nlog的。其实就跟点分治的时间复杂度证明一样。用vector来开并且加上函数resize()就可以办到了。)

    这道题花了整整一天才写出来。。。一直RE(实际是WA,毕竟防离线加密,如果答案错了后面输入都是错的),总结一下错误:

    1.想的只用一个树状数组维护,实际上为了容斥必须要用上第二个树状数组。

    2.更新时,一开始要把自己丢在自己的第二个树状数组里面

    3.2这玩意肯定要写在爬树循环外面啊(你是SB吗)

    4.应该用qsum而不是query去爬树高(一开始脑袋抽了。。)

    5.往树上爬的时候是不会中途退出的,不会因为有一个祖先爬不上去就终止,说不定有一个爷爷就在你旁边你可以过去呢。

    对于点分树的题就想象成爬山吧,我们用每一层的重心将点们分割开来,每次爬树高都是解锁区域,翻过一座高山。

    还有,点分树自己脑补的板子实在太丑陋了。。这里膜拜一下ihopenot大佬,板子神快,我一开始好不容易调出来T了,参考了一下大佬的板子后就rank8了,真乃神人也!

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 100005
     4 #define INF 1e9
     5 #define lowbit(i) ((i)&-(i))
     6 int n,m,head[N],val[N],fa[N][20],dis[N][20],s[N],f[N],dep[N],rt,sz,cnt,ans;
     7 bool vis[N];
     8 vector<int>bit[N],fbit[N];
     9 inline int read(){
    10     int x=0,f=1; char a=getchar();
    11     while(a>'9' || a<'0') {if(a=='-') f=-1; a=getchar();}
    12     while(a<='9' && a>='0') x=x*10+a-'0',a=getchar();
    13     return x*f;
    14 } 
    15 struct edges{
    16     int to,next;
    17 }e[2*N];
    18 inline void insert(){
    19     int u=read(),v=read();
    20     e[cnt]=(edges){v,head[u]};head[u]=cnt++;
    21     e[cnt]=(edges){u,head[v]};head[v]=cnt++;
    22 }
    23 void getroot(int x,int father){
    24     s[x]=1; f[x]=0;
    25     for(int i=head[x];i>=0;i=e[i].next){
    26         if(vis[e[i].to] || father==e[i].to) continue;
    27         getroot(e[i].to,x); s[x]+=s[e[i].to];
    28         f[x]=max(f[x],s[e[i].to]);
    29     }
    30     f[x]=max(f[x],sz-s[x]);
    31     if(f[x]<f[rt]) rt=x;
    32 }
    33 void getship(int x,int anc,int father,int d){
    34     for(int i=head[x];i>=0;i=e[i].next){
    35      int v=e[i].to;
    36      if(!vis[v] && v!=father) fa[v][++dep[v]]=anc,dis[v][dep[v]]=d,getship(v,anc,x,d+1);
    37     }
    38 }
    39 void Buildtree(int x){
    40     vis[x]=1; getship(x,x,0,1); 
    41     int all=sz; bit[x].resize(all+1); fbit[x].resize(all+1);
    42     for(int i=head[x];i>=0;i=e[i].next){
    43         if(vis[e[i].to]) continue;
    44         sz=s[e[i].to]; if(sz>s[x]) sz=all-s[x];
    45         rt=0; getroot(e[i].to,x); Buildtree(rt);
    46     }
    47 }
    48 inline int qsum(int x,int k){
    49     int ret=val[x],lim=bit[x].size()-1; k=min(k,lim); 
    50     for(int i=k;i;i-=lowbit(i)) ret+=bit[x][i];
    51     return ret;
    52 }
    53 inline int qsum2(int x,int k){
    54     int ret=0,lim=fbit[x].size()-1; k=min(k,lim);
    55     for(int i=k;i;i-=lowbit(i)) ret+=fbit[x][i];
    56     return ret;
    57 }
    58 inline void change(int x,int v){
    59     int d,lim; 
    60     d=dis[x][dep[x]]; lim=bit[x].size()-1;
    61     for(int j=d;j<=lim && j;j+=lowbit(j)) fbit[x][j]+=v;
    62     for(int i=dep[x];i;i--){
    63         d=dis[x][i]; lim=bit[fa[x][i]].size()-1;
    64         for(int j=d;j<=lim;j+=lowbit(j)) bit[fa[x][i]][j]+=v;
    65         d=dis[x][i-1];
    66         for(int j=d;j<=lim && j;j+=lowbit(j)) fbit[fa[x][i]][j]+=v;
    67     }
    68 }
    69 int query(int x,int k){
    70     int ret=qsum(x,k);
    71     for(int i=dep[x];i;i--) if(dis[x][i]<=k)
    72     ret+=qsum(fa[x][i],k-dis[x][i])-qsum2(fa[x][i+1],k-dis[x][i]);
    73     return ret;
    74 }
    75 int main(){
    76     n=read(); m=read(); memset(head,-1,sizeof(head));
    77     for(int i=1;i<=n;i++) val[i]=read();
    78     for(int i=1;i<n;i++) insert();
    79     f[0]=INF; sz=n; getroot(1,0); Buildtree(rt); 
    80     for(int i=1;i<=n;i++) fa[i][dep[i]+1]=i;
    81     for(int i=1;i<=n;i++) change(i,val[i]);
    82     while(m--){
    83         int a=read(),b=read()^ans,c=read()^ans;
    84         if(!a) ans=query(b,c),printf("%d
    ",ans);
    85         else change(b,c-val[b]),val[b]=c;
    86     }
    87     return 0;
    88 }
  • 相关阅读:
    css 三角形
    转盘
    使用history.back()出现"警告: 网页已过期的解决办法"
    jQuery 左侧滑动
    Go语言数组的使用
    Go的变量作用域
    Go语言中函数的实现
    Go语言循环判断的使用~
    Go基础
    go环境的安装~
  • 原文地址:https://www.cnblogs.com/enigma-aw/p/6209545.html
Copyright © 2020-2023  润新知