题解 树

传送门

非常巧妙而优雅的数据结构题
然而数据是用脚造的

发现又是个修改与给定点满足一定距离的题
模数不同,复杂度瓶颈不一样
所以考虑离线下来根号分治
\(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;
}
posted @ 2021-09-13 19:25  Administrator-09  阅读(20)  评论(0编辑  收藏  举报