BZOJ 4372/3370 烁烁的游戏/震波 (动态点分治+线段树)

烁烁的游戏 题目大意:

给你一棵$n$个节点的树,有$m$次操作,询问某个节点的权值,或者将与某个点$x$距离不超过$d$的所有节点的权值都增加$w$

动态点分裸题

每个节点开一棵权值线段树

对于修改操作,它从$x$开始,像一个涟漪扩散,对它周围与它距离$leq d$的所有节点造成$w$点贡献

为了记录这个操作的贡献,我们寻找树分治每一层中 包含这个节点的那个点分树的重心$root$

在$root$处记录贡献,开一棵动态开点权值线段树,记录与这个节点距离为$d$的贡献总和,显然在$root$周围扩散范围是$d-dis(x,root)$

还要去掉包含$x$子树的贡献,所以每个节点要再开一个,记录对于父重心需要去掉的贡献

每次查询都沿着点分重心往上跳,因为修改的过程是在线段树上打差分,所以在当前重心查询$d-dis(x,root)$的后缀和即可

由于每次修改都要不断网上跳重心,一共要修改$log$次,每次都要求距离,所以采用欧拉序求$LCA$减小常数

空间是$O(nlog^{2}n)$的,容易被卡,记录当前节点最大能扩散的范围,即当前节点接管的那部分子树内节点的最大深度,非常有效地优化了空间

实在是讲不太明白,大家可以看代码

  1 #include <map>
  2 #include <queue>
  3 #include <vector>
  4 #include <cstdio>
  5 #include <cstring>
  6 #include <algorithm>
  7 #define N1 101000
  8 #define ll long long
  9 #define dd double
 10 #define inf 0x3f3f3f3f3f3f3f3fll
 11 using namespace std;
 12 
 13 int gint()
 14 {
 15     int ret=0,fh=1;char c=getchar();
 16     while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();}
 17     while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();}
 18     return ret*fh;
 19 }
 20 
 21 struct SEG{
 22 int sum[N1*150],ls[N1*150],rs[N1*150],rm[N1],rf[N1],tot;
 23 void pushup(int rt){sum[rt]=sum[ls[rt]]+sum[rs[rt]];}
 24 void update(int x,int l,int r,int &rt,int w)
 25 {
 26     if(!rt) rt=++tot;
 27     if(l==r) {sum[rt]+=w;return;}
 28     int mid=(l+r)>>1;
 29     if(x<=mid) update(x,l,mid,ls[rt],w);
 30     else update(x,mid+1,r,rs[rt],w);
 31     pushup(rt);
 32 }
 33 int query(int L,int R,int l,int r,int rt)
 34 {
 35     if(!rt) return 0;
 36     if(L<=l&&r<=R) return sum[rt];
 37     int mid=(l+r)>>1,ans=0;
 38     if(L<=mid) ans+=query(L,R,l,mid,ls[rt]);
 39     if(R>mid) ans+=query(L,R,mid+1,r,rs[rt]);
 40     return ans;
 41 }
 42 }s;
 43 
 44 struct Edge{
 45 int to[N1<<1],nxt[N1<<1],head[N1],cte;
 46 void ae(int u,int v)
 47 {cte++;to[cte]=v,nxt[cte]=head[u],head[u]=cte;}
 48 }e;
 49 
 50 int n,m,T;
 51 namespace tr{
 52 int dep[N1],ff[N1<<1][20],st[N1],id[N1<<1],lg[N1<<1],tot;
 53 void dfs1(int u,int dad)
 54 {
 55     id[++tot]=u; st[u]=tot; ff[tot][0]=u;
 56     for(int j=e.head[u];j;j=e.nxt[j])
 57     {
 58         int v=e.to[j]; if(v==dad) continue;
 59         dep[v]=dep[u]+1; dfs1(v,u); id[++tot]=u; ff[tot][0]=u;
 60     }
 61 }
 62 void get_st()
 63 {
 64     int i,j;
 65     for(lg[1]=0,i=2;i<=tot;i++) lg[i]=lg[i>>1]+1;
 66     for(j=1;j<=lg[tot];j++)
 67         for(i=1;i+(1<<j)-1<=tot;i++)
 68         ff[i][j]=dep[ ff[i][j-1] ]<dep[ ff[i+(1<<(j-1))][j-1] ]?ff[i][j-1]:ff[i+(1<<(j-1))][j-1];
 69 }
 70 int dis(int x,int y)
 71 {
 72     int tx=min(st[x],st[y]),ty=max(st[x],st[y]),L=ty-tx+1;
 73     int fa=dep[ ff[tx][lg[L]] ]<dep[ ff[ty-(1<<lg[L])+1][lg[L]] ]?ff[tx][lg[L]]:ff[ty-(1<<lg[L])+1][lg[L]];
 74     return dep[x]+dep[y]-2*dep[fa];
 75 }
 76 void init(){dfs1(1,-1);get_st();}
 77 };
 78 
 79 using tr::dis;
 80 
 81 int ms[N1],sz[N1],dep[N1],mad[N1],use[N1],fa[N1],tsz,G;
 82 void dfs(int u,int dad,int g)
 83 {
 84     mad[g]=max(mad[g],dep[u]); sz[u]=1;
 85     for(int j=e.head[u];j;j=e.nxt[j])
 86     {
 87         int v=e.to[j]; if(v==dad||use[v]) continue;
 88         dep[v]=dep[u]+1; dfs(v,u,g); sz[u]+=sz[v];
 89     }
 90 }
 91 void gra(int u,int dad)
 92 {   
 93     sz[u]=1; ms[u]=0;
 94     for(int j=e.head[u];j;j=e.nxt[j])
 95     {
 96         int v=e.to[j]; if(use[v]||v==dad) continue;
 97         gra(v,u); sz[u]+=sz[v]; ms[u]=max(ms[u],sz[v]);
 98     }
 99     ms[u]=max(ms[u],tsz-sz[u]);
100     if(ms[u]<ms[G]) G=u;
101 }
102 void main_dfs(int u)
103 {
104     use[u]=1; dep[u]=0; dfs(u,-1,u);
105     for(int j=e.head[u];j;j=e.nxt[j])
106     {
107         int v=e.to[j]; if(use[v]) continue;
108         G=0; tsz=sz[v]; gra(v,-1); fa[G]=u;
109         main_dfs(G);
110     }
111 }
112 void modify(int x,int K,int w)
113 {
114     int i,D;
115     for(i=x;i;i=fa[i])
116     {
117         D=dis(x,i);
118         if(D<=K) s.update(min(mad[i],K-D),0,mad[i],s.rm[i],w);
119         if(!fa[i]) break;
120         D=dis(x,fa[i]);
121         if(D<=K) s.update(min(mad[fa[i]],K-D),0,mad[fa[i]],s.rf[i],w);
122     }
123 }
124 int query(int x)
125 {
126     int i,D,ans=0;
127     for(i=x;i;i=fa[i])
128     {
129         D=dis(x,i);
130         if(D<=mad[i]) ans+=s.query(D,mad[i],0,mad[i],s.rm[i]);
131         if(!fa[i]) break;
132         D=dis(x,fa[i]); 
133         if(D<=mad[fa[i]]) ans-=s.query(D,mad[fa[i]],0,mad[fa[i]],s.rf[i]);
134     }
135     return ans;
136 }
137 
138 int main()
139 {
140     scanf("%d%d",&n,&m);
141     int i,j,x,y,w,ans=0;
142     for(i=1;i<n;i++) x=gint(), y=gint(), e.ae(x,y), e.ae(y,x);
143     tr::init();
144     ms[0]=tsz=n; G=0; gra(1,-1); gra(G,-1);
145     main_dfs(G); char str[10];
146     for(i=1;i<=m;i++)
147     {
148         scanf("%s",str);
149         if(str[0]=='M'){
150             x=gint(); y=gint(); w=gint();
151             modify(x,y,w);
152         }else{
153             x=gint();
154             ans=query(x);
155             printf("%d
",ans);
156         }
157     }
158     return 0;
159 }

震波那道题和这道题非常像,只不过是点的修改和子树的查询

但由于我一直被卡常,没脸放代码了qwq

原文地址:https://www.cnblogs.com/guapisolo/p/10201431.html