题解 帝国防卫

传送门

  • 关于「对子树内某个深度的所有点进行操作」的一个可能的处理方法:建 BFS 序

于是有个 \(O(n\log^3n)\) 的做法:
对于每个修改,枚举 log 个祖先,每个向下计算 log 层贡献,单次用 log 的线段树

  • 一种支持区间加,查询区间内满足 \(val_i\geqslant c_i\)\(c_i\) 为定值)的技巧:
    将位置 \(i\) 初始权值设为 \(c_i\),线段树上维护区间 \(\min\)
    修改的时候若 \(\min \leqslant dat\) 就递归下去,否则使用懒标记
    当一个叶子节点的 \(val\leqslant 0\) 的时候,令 \(cnt_i=1,val_i=\inf\)
    这样易证复杂度是均摊 \(O(n\log n)\)

貌似有两个 log 的虚树做法?
还有一个来自 @zero4338 的应该是两个 log 的整体二分做法
核心在于在 \(O(\log n)\) 内完成单次修改
修改 \(x\) 时,使 \(val_x\gets val_x+y\)
枚举祖先使 \(val_{fa_x}\gets val_{fa_x}+\lfloor\frac{y}{2}\rfloor\),以此类推
查询 \(x\) 时向上枚举 log 个祖先计算贡献
发现这样会算多,所以修改时再容斥掉算多的部分就好
具体地,修改 \(x\) 时,使 \(val_x\gets val_x+y-\lfloor\frac{y}{4}\rfloor\) (应该是 4 吧我没算错吧)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define INF2 0x3f3f3f3f3f3f3f3f
#define N 100010
#define fir first
#define sec second
#define pb push_back
#define ll long long
//#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, m;
int head[N], c[N], top[N], val[N], siz[N], id[N], ecnt, tot;
struct edge{int to, next;}e[N<<1];
inline void add(int s, int t) {e[++ecnt]={t, head[s]}; head[s]=ecnt;}

void dfs1(int u, int fa) {
	top[u]=fa; siz[u]=1; id[u]=++tot;
	for (int i=head[u],v; ~i; i=e[i].next) {
		v = e[i].to;
		if (v==fa) continue;
		dfs1(v, u);
		siz[u]+=siz[v];
	}
}

namespace force{
	void dfs2(int u, int fa, int dlt) {
		if (!dlt) return ;
		val[u]+=dlt;
		for (int i=head[u],v; ~i; i=e[i].next) {
			v = e[i].to;
			if (v==fa) continue;
			dfs2(v, u, dlt/2);
		}
	}
	int dfs3(int u, int fa) {
		int ans=val[u]>=c[u];
		for (int i=head[u],v; ~i; i=e[i].next) {
			v = e[i].to;
			if (v==fa) continue;
			ans+=dfs3(v, u);
		}
		return ans;
	}
	void solve() {
		for (int i=1,x,y; i<=m; ++i) {
			if (read()&1) {
				x=read(); y=read();
				dfs2(x, 0, y);
			}
			else {
				x=read();
				printf("%d\n", dfs3(x, top[x]));
			}
		}
	}
}

namespace task1{
	int bit[N];
	inline void upd(int i, int dat) {for (; i<=n; i+=i&-i) bit[i]+=dat;}
	inline int query(int i) {int ans=0; for (; i; i-=i&-i) ans+=bit[i]; return ans;}
	void dfs2(int u, int fa, int dlt) {
		if (!dlt) return ;
		if (val[u]<c[u] && val[u]+dlt>=c[u]) upd(id[u], 1);
		val[u]+=dlt;
		for (int i=head[u],v; ~i; i=e[i].next) {
			v = e[i].to;
			if (v==fa) continue;
			dfs2(v, u, dlt/2);
		}
	}
	void solve() {
		for (int i=1,x,y; i<=m; ++i) {
			if (read()&1) {
				x=read(); y=read();
				dfs2(x, 0, y);
			}
			else {
				x=read();
				printf("%d\n", query(id[x]+siz[x]-1)-query(id[x]-1));
			}
		}
	}
}

namespace task{
	bool vis[N];
	int id[N], rk[N], bit[N], fa[N], tot;
	queue<int> q;
	pair<int, int> rg[N][25];
	inline void upd(int i) {for (; i<=n; i+=i&-i) ++bit[i];}
	inline int query(int i) {int ans=0; for (; i; i-=i&-i) ans+=bit[i]; return ans;}
	int tl[N<<2], tr[N<<2], tag[N<<2]; ll mn[N<<2];
	#define tl(p) tl[p]
	#define tr(p) tr[p]
	#define mn(p) mn[p]
	#define tag(p) tag[p]
	#define pushup(p) mn(p)=min(mn(p<<1), mn(p<<1|1))
	void spread(int p) {
		if (!tag(p)) return ;
		mn(p<<1)-=tag(p); tag(p<<1)+=tag(p);
		mn(p<<1|1)-=tag(p); tag(p<<1|1)+=tag(p);
		tag(p)=0;
	}
	void build(int p, int l, int r) {
		tl(p)=l; tr(p)=r;
		if (l==r) {mn(p)=c[rk[l]]; return ;}
		int mid=(l+r)>>1;
		build(p<<1, l, mid);
		build(p<<1|1, mid+1, r);
		pushup(p);
	}
	void upd(int p, int l, int r, int val) {
		// cout<<"upd: "<<p<<' '<<l<<' '<<r<<' '<<val<<endl;
		if (tl(p)==tr(p)) {
			if (mn(p)<=val) upd(::id[rk[tl(p)]]), mn(p)=INF2; //, cout<<"add: "<<tl(p)<<' '<<rk[tl(p)]<<endl;
			else mn(p)-=val;
			return ;
		}
		if (l<=tl(p)&&r>=tr(p)&&mn(p)>val) {mn(p)-=val; tag(p)+=val; return ;}
		spread(p);
		int mid=(tl(p)+tr(p))>>1;
		if (l<=mid) upd(p<<1, l, r, val);
		if (r>mid) upd(p<<1|1, l, r, val);
		pushup(p);
	}
	void bfs() {
		q.push(1); vis[1]=1;
		while (q.size()) {
			int u=q.front(); q.pop();
			rk[id[u]=++tot]=u;
			rg[u][0]={tot, tot};
			for (int now=fa[u],lst=u,dis=1; now&&dis<25; lst=now,now=fa[now],++dis) {
				rg[now][dis].fir=min(rg[now][dis].fir, tot);
				rg[now][dis].sec=max(rg[now][dis].sec, tot);
			}
			for (int i=head[u],v; ~i; i=e[i].next) {
				v = e[i].to;
				if (vis[v]) continue;
				q.push(v);
				fa[v]=u; vis[v]=1;
			}
		}
	}
	void solve() {
		for (int i=1; i<=n; ++i) for (int j=0; j<25; ++j) rg[i][j].fir=INF;
		bfs();
		build(1, 1, n);
		// cout<<"id: "; for (int i=1; i<=n; ++i) cout<<id[i]<<' '; cout<<endl;
		// int x=3, y=1; cout<<rg[x][y].fir<<' '<<rg[x][y].sec<<endl;
		// cout<<"fa: "; for (int i=1; i<=n; ++i) cout<<fa[i]<<' '; cout<<endl;
		for (int i=1,x,y; i<=m; ++i) {
			// cout<<"i: "<<i<<endl;
			if (read()&1) {
				x=read(); y=read();
				upd(1, id[x], id[x], y);
				for (int j=1,val=y>>1; val&&rg[x][j].fir<=rg[x][j].sec; ++j,val>>=1)
					upd(1, rg[x][j].fir, rg[x][j].sec, val);
				for (int now=fa[x],lst=x,val=y>>1; now&&val; lst=now,now=fa[now],val>>=1) {
					upd(1, id[now], id[now], val);
					// cout<<"now,lst: "<<now<<' '<<lst<<endl;
					for (int j=1,tval=val>>1; tval&&rg[now][j].fir<=rg[now][j].sec; ++j,tval>>=1) {
						if (rg[lst][j-1].fir<=rg[lst][j-1].sec) {
							if (rg[now][j].fir<rg[lst][j-1].fir) upd(1, rg[now][j].fir, rg[lst][j-1].fir-1, tval);
							if (rg[lst][j-1].sec<rg[now][j].sec) upd(1, rg[lst][j-1].sec+1, rg[now][j].sec, tval);
						}
						else upd(1, rg[now][j].fir, rg[now][j].sec, tval);
					}
				}
			}
			else {
				x=read();
				// cout<<"x: "<<x<<' '<<::id[x]<<' '<<siz[x]<<endl;
				printf("%d\n", query(::id[x]+siz[x]-1)-query(::id[x]-1));
			}
		}
	}
}

signed main()
{
	freopen("empire.in", "r", stdin);
	freopen("empire.out", "w", stdout);

	n=read();
	memset(head, -1, sizeof(head));
	for (int i=1; i<=n; ++i) c[i]=read();
	for (int i=1,u,v; i<n; ++i) {
		u=read(); v=read();
		add(u, v); add(v, u);
	}
	dfs1(1, 0);
	m=read();
	// force::solve();
	task::solve();
	
	return 0;
}
posted @ 2022-03-03 21:44  Administrator-09  阅读(1)  评论(0编辑  收藏  举报