zoukankan      html  css  js  c++  java
  • BZOJ

    两种操作:

    1.查询与树上结点x距离不超过k的结点权值之和

    2.将结点x的权值修改为y

    点分树模板题。

    首先考虑一种比较暴力的做法:用树形dp的思想,将树转化成有根树,设f[u][k]为结点u子树下与其距离不超过k的点权和,则ans(x,k)=f[u][k]+f[fa[u]][k-1]-f[u][k-2]+f[fa[fa[u]]][k-2]-f[fa[u]][k-3]...,可如果树太高的话就GG了,要是能把树高变成logn级别的就好了。

    建立点分树(点分治过程中形成的树),每个结点维护两个树状数组,一个维护以该结点为重心的各个距离上的权值和,一个维护其虚父亲(点分树上的父亲)在“该结点方向”上的各个距离上的权值和(用于容斥)。还要维护点分树上每个结点到其所有祖先结点在原树上的距离,修改和询问就从当前结点开始不断向上跳即可。(点分树的树高是logn级别的,可以暴力往上跳)

     总复杂度$O(nlogn+qlog^2n)$

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 const int N=1e5+10,inf=0x3f3f3f3f;
     5 struct E {int v,nxt;} e[N<<1];
     6 int a[N],hd[N],ne,n,Q,siz[N],mx[N],vis[N],RT,tot,cnt[N],fa[N],rnk[N],ds[N][20];
     7 int buf[N*40],*ptr=buf;
     8 struct BIT {
     9     int *c,n;
    10     int lb(int x) {return x&-x;}
    11     void add(int u,int x) {for(; u<=n; u+=lb(u))c[u]+=x;}
    12     int get(int u) {int ret=0; for(u=min(u,n); u; u-=lb(u))ret+=c[u]; return ret;}
    13     void build(int* a) {
    14         for(int i=1; i<=n; ++i)c[i]=a[i];
    15         for(int i=1; i<=n; ++i)if(i+lb(i)<=n)c[i+lb(i)]+=c[i];
    16     }
    17 } c[N][2];
    18 BIT newBIT(int n) {BIT t= {ptr,n}; ptr+=n+1; return t;}
    19 void link(int u,int v) {e[ne]= (E) {v,hd[u]},hd[u]=ne++;}
    20 void getrt(int u,int f) {
    21     siz[u]=1,mx[u]=0;
    22     for(int i=hd[u]; ~i; i=e[i].nxt) {
    23         int v=e[i].v;
    24         if(vis[v]||v==f)continue;
    25         getrt(v,u),siz[u]+=siz[v],mx[u]=max(mx[u],siz[v]);
    26     }
    27     mx[u]=max(mx[u],tot-siz[u]);
    28     if(mx[u]<mx[RT])RT=u;
    29 }
    30 void getdis(int u,int f,int d,int rk) {
    31     ds[u][rk]=d;
    32     cnt[d+1]+=a[u];
    33     for(int i=hd[u]; ~i; i=e[i].nxt) {
    34         int v=e[i].v;
    35         if(vis[v]||v==f)continue;
    36         getdis(v,u,d+1,rk);
    37     }
    38 }
    39 void cal(int u,int f) {
    40     int m=1;
    41     for(; cnt[m]; ++m);
    42     --m;
    43     c[u][f]=newBIT(m);
    44     c[u][f].build(cnt);
    45     for(int i=1; i<=m; ++i)cnt[i]=0;
    46 }
    47 void solve(int u,int rk) {
    48     rnk[u]=rk;
    49     getdis(u,0,0,rk),cal(u,0),vis[u]=1;
    50     for(int i=hd[u]; ~i; i=e[i].nxt) {
    51         int v=e[i].v;
    52         if(vis[v])continue;
    53         getdis(v,0,0,rk+1),RT=0,tot=siz[v];
    54         getrt(v,0),cal(RT,1),fa[RT]=u,solve(RT,rk+1);
    55     }
    56 }
    57 void upd(int u,int x) {
    58     x-=a[u],a[u]+=x;
    59     int dis=0;
    60     c[u][0].add(dis+1,x);
    61     for(int v=u; fa[v]; v=fa[v]) {
    62         dis=ds[u][rnk[fa[v]]];
    63         c[fa[v]][0].add(dis+1,x),c[v][1].add(dis,x);
    64     }
    65 }
    66 int qry(int u,int d) {
    67     int ret=0,dis=d;
    68     ret+=c[u][0].get(dis+1);
    69     for(int v=u; fa[v]; v=fa[v]) {
    70         dis=d-ds[u][rnk[fa[v]]];
    71         if(dis>=0)ret+=c[fa[v]][0].get(dis+1)-c[v][1].get(dis);
    72     }
    73     return ret;
    74 }
    75 int main() {
    76     memset(hd,-1,sizeof hd),ne=0;
    77     scanf("%d%d",&n,&Q);
    78     for(int i=1; i<=n; ++i)scanf("%d",&a[i]);
    79     for(int i=1; i<n; ++i) {
    80         int u,v;
    81         scanf("%d%d",&u,&v);
    82         link(u,v);
    83         link(v,u);
    84     }
    85     mx[0]=inf,RT=0,tot=n,getrt(1,0),fa[RT]=0,solve(RT,0);
    86     for(int la=0; Q--;) {
    87         int f,u,x;
    88         scanf("%d%d%d",&f,&u,&x);
    89         u^=la,x^=la;
    90         if(f==0)printf("%d
    ",la=qry(u,x));
    91         else upd(u,x);
    92     }
    93     return 0;
    94 }

     还有一种做法是边分树,需要将原树转化成二叉树,稍微麻烦点但省去了容斥的过程,感觉相对更容易理解。

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 typedef long long ll;
      4 const int N=4e5+10,inf=0x3f3f3f3f;
      5 struct E {int v,c,nxt;} e[N];
      6 int a[N],hd[N],ne,n,Q,siz[N],vis[N],cnt[N],fa[N],tot,rt,mx,edge[N],mxd,rnk[N],ds[N][20];
      7 int buf[N*40],*ptr=buf;
      8 struct BIT {
      9     int *c,n;
     10     int lb(int x) {return x&-x;}
     11     void add(int u,int x) {for(; u<=n; u+=lb(u))c[u]+=x;}
     12     int get(int u) {int ret=0; for(u=min(u,n); u; u-=lb(u))ret+=c[u]; return ret;}
     13     void build(int* a) {
     14         for(int i=1; i<=n; ++i)c[i]=a[i];
     15         for(int i=1; i<=n; ++i)if(i+lb(i)<=n)c[i+lb(i)]+=c[i];
     16     }
     17 } c[N];
     18 BIT newBIT(int n) {BIT t= {ptr,n}; ptr+=n+1; return t;}
     19 void link(int u,int v,int c) {e[ne]= (E) {v,c,hd[u]},hd[u]=ne++;}
     20 vector<E> g[N];
     21 void rebuild(int u,int f) {
     22     int w=u;
     23     for(int i=hd[u]; ~i; i=e[i].nxt) {
     24         int v=e[i].v;
     25         if(v==f)continue;
     26         rebuild(v,u);
     27         g[w].push_back({v,1,0});
     28         if(~e[i].nxt&&~e[e[i].nxt].nxt)g[w].push_back({++tot,0,0}),w=tot;
     29     }
     30 }
     31 void rebuild() {
     32     tot=n,rebuild(1,0);
     33     memset(hd,-1,sizeof hd),ne=0;
     34     for(int i=1; i<=tot; ++i) {
     35         for(int j=0; j<g[i].size(); ++j)
     36             link(i,g[i][j].v,g[i][j].c),link(g[i][j].v,i,g[i][j].c);
     37         g[i].clear();
     38     }
     39 }
     40 void getrt(int u,int f,int sz) {
     41     siz[u]=1;
     42     for(int i=hd[u]; ~i; i=e[i].nxt) {
     43         int v=e[i].v;
     44         if(vis[i]||v==f)continue;
     45         getrt(v,u,sz),siz[u]+=siz[v];
     46         int t=max(siz[v],sz-siz[v]);
     47         if(t<mx)mx=t,rt=i;
     48     }
     49 }
     50 void getdis(int u,int f,int d,int rk) {
     51     ds[u][rk]=d;
     52     if(u<=n)cnt[d+1]+=a[u],mxd=max(mxd,d+1);
     53     for(int i=hd[u]; ~i; i=e[i].nxt) {
     54         int v=e[i].v,c=e[i].c;
     55         if(vis[i]||v==f)continue;
     56         getdis(v,u,d+c,rk);
     57     }
     58 }
     59 void cal(int u) {
     60     c[u]=newBIT(mxd);
     61     c[u].build(cnt);
     62     for(int i=1; i<=mxd; ++i)cnt[i]=0;
     63 }
     64 void solve(int u,int f,int sz,int rk) {
     65     if(sz==1) {edge[u]=f; return;}
     66     mx=inf,getrt(u,0,sz);
     67     int t=rt;
     68     vis[t]=vis[t^1]=1;
     69     fa[t]=fa[t^1]=f;
     70     rnk[t]=rnk[t^1]=rk;
     71     mxd=0,getdis(e[t].v,0,0,rk),cal(t);
     72     mxd=0,getdis(e[t^1].v,0,0,rk),cal(t^1);
     73     int a=siz[e[t].v],b=sz-siz[e[t].v];
     74     solve(e[t].v,rt,a,rk+1),solve(e[t^1].v,t^1,b,rk+1);
     75 }
     76 void upd(int u,int x) {
     77     x-=a[u],a[u]+=x;
     78     for(int t=edge[u]; ~t; t=fa[t]) {
     79         int dis=ds[u][rnk[t]];
     80         c[t].add(dis+1,x);
     81     }
     82 }
     83 int qry(int u,int d) {
     84     int ret=a[u];
     85     for(int t=edge[u]; ~t; t=fa[t]) {
     86         int dis=d-(ds[u][rnk[t]]+e[t].c);
     87         if(dis>=0)ret+=c[t^1].get(dis+1);
     88     }
     89     return ret;
     90 }
     91 int main() {
     92     memset(hd,-1,sizeof hd),ne=0;
     93     scanf("%d%d",&n,&Q);
     94     for(int i=1; i<=n; ++i)scanf("%d",&a[i]);
     95     for(int i=1; i<n; ++i) {
     96         int u,v;
     97         scanf("%d%d",&u,&v);
     98         link(u,v,0);
     99         link(v,u,0);
    100     }
    101     rebuild();
    102     solve(1,-1,tot,0);
    103     for(int la=0; Q--;) {
    104         int f,u,x;
    105         scanf("%d%d%d",&f,&u,&x);
    106         u^=la,x^=la;
    107         if(f==0)printf("%d
    ",la=qry(u,x));
    108         else upd(u,x);
    109     }
    110     return 0;
    111 }
  • 相关阅读:
    Orika对象复制教程(完美笔记)
    JAVA-开发构建Gradle项目安装使用教程
    Java中传入一个时间范围,取出该时间范围内所有日期的集合
    线程安全之原子操作
    Java内存模型以及线程安全的可见性问题
    Java线程池的应用
    Java中实现线程的方式
    线程通信
    线程状态
    CPU缓存和内存屏障
  • 原文地址:https://www.cnblogs.com/asdfsag/p/12513986.html
Copyright © 2011-2022 走看看