• 震波——动态点分治+线段树


    题目

    【题目描述】

    在一片土地上有 $N$ 个城市,通过 $N-1$ 条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为 $1$,其中第 $i$ 个城市的价值为 $value[i]$。
    不幸的是,这片土地常常发生地震,并且随着时代的发展,城市的价值也往往会发生变动。

    接下来你需要在线处理 $M$ 次操作:
    - $0~x~k$ 表示发生了一次地震,震中城市为 $x$ ,影响范围为 $k$ ,所有与 $x$ 距离不超过 $k$ 的城市都将受到影响,该次地震造成的经济损失为所有受影响城市的价值和。
    - $1~x~y$ 表示第$x$个城市的价值变成了 $y$ 。

    为了体现程序的在线性,操作中的 $x$ 、$y$ 、$k$ 都需要异或你程序上一次的输出来解密,如果之前没有输出,则默认上一次的输出为 $0$ 。


    【输入格式】

    第一行包含两个正整数 $N$ 和 $M$ 。

    第二行包含 $N$ 个正整数,第 $i$ 个数表示 $value[i]$ 。

    接下来 $N-1$ 行,每行包含两个正整数$u,v$,表示 $u$ 和 $v$ 之间有一条无向边。

    接下来 $M$ 行,每行包含三个数,表示 $M$ 次操作。


    【输出格式】
    包含若干行,对于每个询问输出一行一个正整数表示答案。
    【样例输入】

    8 1
    1 10 100 1000 10000 100000 1000000 10000000
    1 2
    1 3
    2 4
    2 5
    3 6
    3 7
    3 8
    0 3 1


    【样例输出】
    11100101
    【数据范围与提示】

    $1 le N,M le 100000$

    $1 le u,v,x le N $

    $1 le value[i],y le 10000 $

    $ 0 le k le N-1 $

    题解

    要求树上和一个点距离不超过 $k$ 的所有点,很容易想到动态点分治

    开 $ n $ 棵权值线段树,记录当前点分中心距离为 $ v $ 的点的个数

    考虑在点分树上查询,会发现在 $ x $ 统计过答案的点有可能在 $ fa[x] $ 上也被统计

    考虑容斥,再开 $ n $ 棵线段树,记录从当前点分中心 $ x $ 经过 $ fa[x] $ 距离为 $ v $ 的权值和,查询时扣掉即可

    时间效率:$ O(nlog^2 n) $

    代码

      1 #include<bits/stdc++.h>
      2 #define LL long long
      3 #define il inline
      4 #define re register
      5 #define _(d) while(d(isdigit(ch=getchar())))
      6 using namespace std;
      7 il int R(){
      8     int x;bool f=1;char ch;_(!)if(ch=='-')f=0;x=ch^48;
      9     _()x=(x<<3)+(x<<1)+(ch^48);return f?x:-x;}
     10 const int N=2e5+10;
     11 int n,m,ans,f[N],top[N],dep[N],sz[N],son[N],head[N],cnt,Mx,Rt,Sz,fa[N],siz[N],val[N],rot[N<<1],tot;
     12 bool vis[N];
     13 struct seg{int ls,rs,v;}tr[N<<6];
     14 struct edge{int to,nex;}e[N<<1];
     15 il void add(int s,int t){e[++cnt]=(edge){t,head[s]},head[s]=cnt;}
     16 il void dfs(int x,int far){
     17     f[x]=far,sz[x]=1,dep[x]=dep[far]+1;
     18     for(re int v,k=head[x];k;k=e[k].nex)
     19         if((v=e[k].to)!=far){
     20             dfs(v,x),sz[x]+=sz[v];
     21             if(sz[v]>sz[son[x]])son[x]=v;
     22         }
     23     return;
     24 }
     25 il void DFS(int x,int far){
     26     top[x]=far;
     27     if(son[x])DFS(son[x],far);
     28     for(re int k=head[x],v;k;k=e[k].nex)
     29         if((v=e[k].to)!=f[x]&&v!=son[x])
     30             DFS(v,v);
     31 }
     32 il int lca(int x,int y){
     33     while(top[x]^top[y]){
     34         if(dep[top[x]]<dep[top[y]])swap(x,y);
     35         x=f[top[x]];
     36     }
     37     return dep[x]<dep[y]?x:y;
     38 }
     39 il int get(int u,int v){return dep[u]+dep[v]-2*dep[lca(u,v)];}
     40 il void getrot(int u,int far){
     41     int mx=0;siz[u]=1;
     42     for(re int k=head[u],v;k;k=e[k].nex)
     43         if((v=e[k].to)!=far&&!vis[v])
     44             getrot(v,u),siz[u]+=siz[v],mx=max(mx,siz[v]);
     45     mx=max(mx,Sz-siz[u]);
     46     if(mx<Mx)Mx=mx,Rt=u;
     47     return;
     48 }
     49 il int getsize(int u,int far){
     50     siz[u]=1;
     51     for(re int k=head[u],v;k;k=e[k].nex)
     52         if((v=e[k].to)!=far&&!vis[v])
     53             siz[u]+=getsize(v,u);
     54     return siz[u];
     55 }
     56 void slove(int u,int far){
     57     Mx=1e9,getrot(u,0),vis[Rt]=1;
     58     fa[Rt]=far,far=Rt;
     59     for(re int k=head[Rt],v;k;k=e[k].nex)
     60         if(!vis[v=e[k].to])Sz=getsize(v,0),slove(v,far);
     61 }
     62 #define Ls tr[rt].ls
     63 #define Rs tr[rt].rs
     64 il void change(int &rt,int l,int r,int k,int x){
     65     if(!rt)rt=++tot;
     66     tr[rt].v+=x;
     67     if(l==r)return;
     68     int mid=(l+r)>>1;
     69     if(k<=mid)change(Ls,l,mid,k,x);
     70     else change(Rs,mid+1,r,k,x);
     71     return;
     72 }
     73 il int query(int rt,int l,int r,int qr){
     74     if(!rt)return 0;
     75     if(qr>=r)return tr[rt].v;
     76     int mid=(l+r)>>1,res=0;
     77     if(qr>mid)res=tr[Ls].v+query(Rs,mid+1,r,qr);
     78     else res=query(Ls,l,mid,qr);
     79     return res;
     80 }
     81 il void update(int x,int v){
     82     change(rot[x],0,n,0,v);
     83     for(re int i=x;fa[i];i=fa[i]){
     84         int dis=get(x,fa[i]);
     85         change(rot[fa[i]],0,n,dis,v);
     86         change(rot[i+n],0,n,dis,v);
     87     }
     88 }
     89 il int ask(int x,int y){
     90     int res=query(rot[x],0,n,y);
     91     for(re int i=x;fa[i];i=fa[i]){
     92         int dis=get(x,fa[i]);
     93         if(dis>y)continue;
     94         res+=query(rot[fa[i]],0,n,y-dis)-query(rot[i+n],0,n,y-dis);
     95     }
     96     return res;
     97 }
     98 int main(){
     99     n=R(),m=R();
    100     for(re int i=1;i<=n;i++)val[i]=R();
    101     for(re int i=1,u,v;i<n;i++)
    102         u=R(),v=R(),add(u,v),add(v,u);
    103     dfs(1,0),DFS(1,1),Sz=n,slove(1,0);
    104     for(re int i=1;i<=n;i++)update(i,val[i]);
    105     for(re int i=1;i<=m;i++){
    106         int op=R(),x=R()^ans,y=R()^ans;
    107         if(op)update(x,y-val[x]),val[x]=y;
    108         else printf("%d
    ",ans=ask(x,y));
    109     }
    110     return 0;
    111 }
    View Code
  • 相关阅读:
    构建之法 读书笔记01
    团队合作第一次会议有感
    浪潮之巅 读书笔记 03
    浪潮之巅 读书笔记 02
    团队介绍
    疫情查询app 开发
    世界疫情信息爬取 及开发查询爬取数据的app
    浪潮之巅 读书笔记 01
    支付宝沙箱配置
    定时器定时执行redis操作定时器执行几次自动停止的问题
  • 原文地址:https://www.cnblogs.com/chmwt/p/10661287.html
Copyright © 2020-2023  润新知