题解 树
非常巧妙而优雅的数据结构题
然而数据是用脚造的
发现又是个修改与给定点满足一定距离的题
模数不同,复杂度瓶颈不一样
所以考虑离线下来根号分治
当 \(x \leqslant \sqrt n\) 时
发现对于一个固定的 \(x\),一次修改能影响的点满足 \((dep_v-dep_u) mod\ x=y\)
即 \(dep_v \ mod\ x = (dep_u+y)mod\ x\)
所以可以枚举 \(x\),对所有修改和询问在上述操作后的余数分别开一个桶
然后在每个余数对应的桶里按输入顺序双指针一遍
对于子树修改
- 这里我们需要一个区间修改,单点查询的东西
有 \(q\) 次区间修改,\(q\sqrt n\) 次单点查询
所以可以分块,修改 \(O(\sqrt n)\),查询 \(O(1)\)
这样就将时间平衡到了 \(O(q\sqrt n)\)
当 \(x > \sqrt n\) 时
发现一个修改最多影响 \(\sqrt n\) 个深度
所以可以对每个深度开一个能影响到这个深度的修改的桶,然后就和上面一样了
然而发现空间复杂度是 \(O(n\sqrt n)\),开不下
有一种方案是调块的大小,也可以过
但有一种更优的方案是从小往大枚举深度,每 \(\sqrt n\) 次暴力重构,求出接下来 \(\sqrt n\) 个深度能修改到它的所有修改
这样的时间复杂度也是 \(O(q\sqrt n)\) 的
所以总时间复杂度 \(O(q\sqrt n)\),空间复杂度 \(O(n+q)\)
非常优秀而巧妙
Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 300010
#define ll long long
#define reg register int
#define pb push_back
//#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n, q;
int head[N], size;
struct edge{int to, next;}e[N<<1];
inline void add(int s, int t) {e[++size].to=t; e[size].next=head[s]; head[s]=size;}
namespace force{
ll val[N];
int fa[N];
void dfs1(int u, int pa) {
fa[u]=pa;
for (int i=head[u],v; ~i; i=e[i].next) {
v = e[i].to;
if (v!=pa) dfs1(v, u);
}
}
void dfs2(int u, int dis, int mod, int r, int dlt) {
if (dis%mod==r) val[u]+=dlt;
for (int i=head[u],v; ~i; i=e[i].next) {
v = e[i].to;
if (v!=fa[u]) dfs2(v, dis+1, mod, r, dlt);
}
}
void solve() {
dfs1(1, 0);
for (int i=1,u,x,y,z; i<=q; ++i) {
if (read()&1) {
u=read(); x=read(); y=read(); z=read();
dfs2(u, 0, x, y, z);
}
else printf("%lld\n", val[read()]);
}
}
}
namespace task{
int order[N], in[N], siz[N], dep[N], tot, ans[N], len, ccnt, qcnt, bel[N], op[N], mdep;
struct cge{int u, x, y, z, rk; inline void build(int a, int b, int c, int d, int e) {u=a; x=b; y=c; z=d; rk=e;}}q1[N];
struct que{int u, rk, qrk; inline void build(int a, int b, int c) {u=a; rk=b; qrk=c;}}q2[N];
struct array1{
int val[N], tag[N];
int query(int pos) {return val[pos]+tag[bel[pos]];}
void upd(int l, int r, int dat) {
int sid=bel[l], eid=bel[r];
if (sid==eid) {
for (reg i=l; i<=r; ++i) val[i]+=dat;
return ;
}
for (int i=l; bel[i]==sid; ++i) val[i]+=dat;
for (int i=sid+1; i<eid; ++i) tag[i]+=dat;
for (int i=r; bel[i]==eid; --i) val[i]+=dat;
}
}arr1;
struct array2{
int val[N], sum[N];
void upd(int l, int r, int dat) {
val[l]+=dat; sum[bel[l]]+=dat;
val[r+1]-=dat; sum[bel[r+1]]-=dat;
}
int query(int pos) {
int id=bel[pos], ans=0;
for (int i=1; i<id; ++i) ans+=sum[i];
for (int i=pos; bel[i]==id; --i) ans+=val[i];
return ans;
}
}arr2;
vector<cge> v1[N];
vector<que> v2[N];
void dfs(int u, int fa) {
order[++tot]=u;
in[u]=tot;
siz[u]=1;
mdep=max(mdep, dep[u]);
for (int i=head[u],v; ~i; i=e[i].next) {
v = e[i].to;
if (v==fa) continue;
dep[v]=dep[u]+1;
dfs(v, u);
siz[u]+=siz[v];
}
}
void solve() {
len=sqrt(n);
for (int i=1; i<=n; ++i) bel[i]=(i-1)/len+1;
dep[1]=1; dfs(1, 0);
for (int i=1,u,x,y,z; i<=q; ++i) {
//cout<<"i: "<<i<<endl;
if ((op[i]=read())&1) {
u=read(); x=read(); y=read(); z=read();
q1[++ccnt].build(u, x, y, z, i);
}
else ++qcnt, q2[qcnt].build(read(), i, qcnt);
}
for (int i=1; i<=len; ++i) {
//cout<<"i: "<<i<<endl;
for (int j=0; j<=i; ++j)
v1[j].clear(), v2[j].clear();
for (int j=1,pos1=1,pos2=1; j<=q; ++j) {
if (op[j]&1) {
if (q1[pos1].x!=i) {++pos1; continue;}
v1[(dep[q1[pos1].u]+q1[pos1].y)%i].pb(q1[pos1]); //, cout<<"pb: "<<q1[pos1].rk<<endl;
++pos1;
}
else {
v2[dep[q2[pos2].u]%i].pb(q2[pos2]);
++pos2;
}
}
for (int j=0,u; j<i; ++j) {
int siz1=v1[j].size(), siz2=v2[j].size();
int pos1=0, pos2=0;
while (1) {
if (pos1>=siz1 && pos2>=siz2) break;
else if (pos1<siz1 && pos2<siz2) {
if (v1[j][pos1].rk < v2[j][pos2].rk) goto case1;
else goto case2;
}
else if (pos1<siz1) {
case1:
u=v1[j][pos1].u;
arr1.upd(in[u], in[u]+siz[u]-1, v1[j][pos1].z);
++pos1;
}
else {
case2:
ans[v2[j][pos2].qrk]+=arr1.query(in[v2[j][pos2].u]);
++pos2;
}
}
for (auto it:v1[j]) arr1.upd(in[it.u], in[it.u]+siz[it.u]-1, -it.z);
}
}
for (int i=1; i<=n; ++i) v1[i].clear(), v2[i].clear();
for (int i=1; i<=qcnt; ++i) v2[dep[q2[i].u]].pb(q2[i]);
for (int l=1,r; l<=mdep; l=r+1) {
r=min(l+len-1, mdep);
//cout<<"lr: "<<l<<' '<<r<<endl;
double tl=l, tr=r;
for (int j=1; j<=ccnt; ++j) if (q1[j].x>len) {
double tdep=dep[q1[j].u], y=q1[j].y, x=q1[j].x;
double t1=(tl-tdep-y)/x, t2=(tr-tdep-y)/x;
t1=max(t1, 0.0);
if (t1>t2) continue;
int t3=ceil(t1), t4=floor(t2);
if (t3<=t4) {
//cout<<"t3: "<<t3<<endl;
//cout<<"dep: "<<dep[q1[j].u]<<endl;
assert(t3==t4);
v1[dep[q1[j].u]+q1[j].y+t3*q1[j].x].pb(q1[j]); //, cout<<"pb: "<<dep[q1[j].u]+q1[j].y+t3<<' '<<q1[j].rk<<endl;
}
}
for (int j=l,u; j<=r; ++j) {
//cout<<"j: "<<j<<endl;
int siz1=v1[j].size(), siz2=v2[j].size();
//cout<<"siz: "<<siz1<<' '<<siz2<<endl;
int pos1=0, pos2=0;
while (1) {
if (pos1>=siz1 && pos2>=siz2) break;
else if (pos1<siz1 && pos2<siz2) {
if (v1[j][pos1].rk < v2[j][pos2].rk) goto case3;
else goto case4;
}
else if (pos1<siz1) {
case3:
u=v1[j][pos1].u;
arr2.upd(in[u], in[u]+siz[u]-1, v1[j][pos1].z);
++pos1;
}
else {
case4:
ans[v2[j][pos2].qrk]+=arr2.query(in[v2[j][pos2].u]);
++pos2;
}
}
for (auto it:v1[j]) arr2.upd(in[it.u], in[it.u]+siz[it.u]-1, -it.z);
}
}
for (int i=1; i<=qcnt; ++i) printf("%d\n", ans[i]);
}
}
signed main()
{
memset(head, -1, sizeof(head));
n=read(); q=read();
for (int i=1,u,v; i<n; ++i) {
u=read(); v=read();
add(u, v); add(v, u);
}
task::solve();
return 0;
}