ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

20210823 数数,数树,鼠树,ckw的树

2021-08-25 06:32:06  阅读:180  来源: 互联网

标签:head 数树 int siz son mm ckw 20210823 mod


考场

乍一看都不好做

仔细想想发现 T1 的绝对值特别好,轮流选剩余的最大/最小值就行了
T2 又要计数,直接想部分分,发现一个 sb 容斥就有 35ps(但数据锅了,只有 25pts)
T3 什么玩意,发现线段树不会操作 6(线段树分裂啊,昨天刚打了板子),LCT 不会操作 2
,但 sub3(只维护黑点) 4(线段树维护序列) 都会
T4 高消直接死了,一分都没有。两个 sub 都是链,什么情况(考场上把 \(1\) 看成 \(i\)了)

迅速写+拍完前两题
想了想 T4 的系数递推,但列出的式子很不可做;貌似也不能高消一次求出所有答案,puts 样例了
感觉 T3 是比较擅长的题型,又想了很久,sub2 也会了(确定联通块后线段树),但直到 10.20 才开始写,最终只写完了 sub1 4

res

rk3 100+28+25+0(显示的是 rk4,因为出榜时 T3 在 judging。。。)

rk1 张王美誉 100+11+60+0
rk2 牛宏昊 100+44+10+0
rk4 付文暄 90+11+10+20(显示的是 rk3 的氪金玩家

总结

想的太浅了,很多地方就差一点,还是要多思考,不要用写代码的勤奋掩盖思维的懒惰。
T3 正解就是在 sub3 的基础上加了个树剖、线段树,T4 给了菊花,sub3 的做法很明显(不过看错题也没啥好说的)

sol

T1

模拟。考场代码:

const int N = 3e5+5;
int n;
LL a[N];

LL ans,pre[N],suf[N];

signed main() {
//	freopen("a.in","r",stdin);
//	freopen("a.out","w",stdout);
	read(n);
	For(i,1,n) read(a[i]); sort(a+1,a+n+1);
	For(i,1,n) pre[i] = pre[i-1] + a[i];
	rFor(i,n,1) suf[i] = suf[i+1] + a[i];
	for(int i = 1, l = 0, r = n+1; i <= n; ++i) {
		if( i & 1 ) {
			++l;
			ans += (a[l] * (l-1) - pre[l-1]) + (suf[r] - a[l] * (n-r+1));
		} else {
			--r;
			ans += (a[r] * l - pre[l]) + (suf[r+1] - a[r] * (n-r));
		}
		write(ans);
	}
	return iocl();
}
T2

发现暴力容斥时边集具体是什么并不重要,只要知道有多少条边即可。考虑树形 DP,设 \(f[u,i,0/1/2/3]\) 为子树 \(u\) 选 \(i\) 条边不合法,点 \(u\) 不选/选入边/选出边/都选的方案数。(显然一个点不能同时使两条入边/出边不合法)

const int N = 5e3+5, mod = 998244353;
int n,mm=1,head[N],to[N*2],w[N*2],nxt[N*2];

int siz[N];
LL ans,fac[N],f[N][N][4],g[N][4];

void dfs(int u,int fa) {
	siz[u] = 1, f[u][0][0] = 1;
	for(int e = head[u], v; v = to[e], e; e = nxt[e]) if( v != fa ) {
		dfs(v,u);
		memset(g,0,sizeof g);
		For(i,0,siz[u]) For(j,0,siz[v]) {
			LL fv = (f[v][j][0]+f[v][j][1]+f[v][j][2]+f[v][j][3]) %mod;
			For(k,0,3) g[i+j][k] += f[u][i][k] * fv %mod;
			if( w[e] )
				g[i+j+1][2] += f[u][i][0] * (f[v][j][0]+f[v][j][2]) %mod,
				g[i+j+1][3] += f[u][i][1] * (f[v][j][0]+f[v][j][2]) %mod;
			else
				g[i+j+1][1] += f[u][i][0] * (f[v][j][0]+f[v][j][1]) %mod,
				g[i+j+1][3] += f[u][i][2] * (f[v][j][0]+f[v][j][1]) %mod;
		}
		siz[u] += siz[v];
		For(i,1,siz[u]) For(j,0,3) f[u][i][j] = g[i][j] %mod;
	}
}

signed main() {
	read(n);
	fac[0] = 1; For(i,1,n) fac[i] = fac[i-1] * i %mod;
	For(i,1,n-1) {
		int x,y; read(x,y);
		to[++mm] = y, w[mm] = 1, nxt[mm] = head[x], head[x] = mm;
		to[++mm] = x, w[mm] = 0, nxt[mm] = head[y], head[y] = mm;
	}
	dfs(1,0);
	For(i,0,n-1)
		ans += (i+1&1?1:-1) * fac[n-i] * (f[1][i][0]+f[1][i][1]+f[1][i][2]+f[1][i][3]) %mod;
	write((ans%mod+mod)%mod);
	return iocl();
}
T3

好题,需要很多 DS 技巧

发现每个白点的权值并不重要,只要知道它归属的黑点即可(可以树剖+set 单 \(\log\) 维护)。线段树维护每个黑点的权值和管辖点数,BIT 辅助
细节较多。

typedef unsigned U;

const int N = 3e5+5;
int n,m,fa[N];

int ind,dep[N],siz[N],son[N],top[N],dfn[N],rdfn[N];
VI to[N];
set<int> s[N];
void dfs1(int u) {
	dep[u] = dep[fa[u]]+1, siz[u] = 1;
	for(int v : to[u]) {
		dfs1(v);
		siz[u] += siz[v];
		if( siz[v] > siz[son[u]] ) son[u] = v;
	}
}
void dfs2(int u,int t) {
	top[u] = t, dfn[u] = ++ind, rdfn[ind] = u;
	if( son[u] ) dfs2(son[u],t);
	for(int v : to[u]) if( v != son[u] ) dfs2(v,v);
}
int belong(int u) {
	for(int v; v = top[u]; u = fa[top[u]])
		if( !s[v].empty() && *s[v].begin() <= dep[u] ) {
			auto it = s[v].upper_bound(dep[u]);
			return rdfn[dfn[u]-(dep[u]-*--it)];
		}
}

struct BIT {
	U t1[N],t2[N];
	void add(int i,U x) { for(int j=i;j<=n;j+=j&-j) t1[j] += x, t2[j] += i*x; }
	U sum(int i)
		{ U res=0; for(int j=i;j;j-=j&-j) res += (i+1)*t1[j]-t2[j]; return res; }
	void modify(int l,int r,U x) { add(l,x), add(r+1,-x); }
	U query(int l,int r) { return sum(r) - sum(l-1); }
} bit;

#define ls (u<<1)
#define rs (u<<1|1)
struct Node { int l,r; U siz,val,sum,add; } t[N*4];
void up(int u) {
	t[u].siz = t[ls].siz + t[rs].siz,
	t[u].val = t[ls].val + t[rs].val,
	t[u].sum = t[ls].sum + t[rs].sum;
}
void down(int u,U x) { t[u].val += x, t[u].sum += t[u].siz*x, t[u].add += x; }
void down(int u) { down(ls,t[u].add), down(rs,t[u].add), t[u].add = 0; }
void build(int u,int l,int r) {
	t[u].l = l, t[u].r = r;
	if( l == r ) return;
	int mid = l+r>>1;
	build(ls,l,mid), build(rs,mid+1,r);
}
void addsiz(int u,int p,U x) {
	if( t[u].l == t[u].r ) return t[u].siz += x, t[u].sum += x*t[u].val, void();
	down(u);
	addsiz( p<=t[ls].r?ls:rs ,p,x);
	up(u);
}
void addval(int u,int l,int r,U x) {
	if( l <= t[u].l && t[u].r <= r ) return down(u,x);
	down(u);
	if( l <= t[ls].r ) addval(ls,l,r,x);
	if( t[rs].l <= r ) addval(rs,l,r,x);
	up(u);
}
void covval(int u,int p,U x) {
	if( t[u].l == t[u].r ) return t[u].val = x, t[u].sum = x*t[u].siz, void();
	down(u);
	covval( p<=t[ls].r?ls:rs ,p,x);
	up(u);
}
U qsiz(int u,int l,int r) {
	if( l > r ) return 0;
	if( l <= t[u].l && t[u].r <= r ) return t[u].siz;
	down(u);
	U res = 0;
	if( l <= t[ls].r ) res = qsiz(ls,l,r);
	if( t[rs].l <= r ) res += qsiz(rs,l,r);
	return res;
}
U qval(int u,int p) {
	if( t[u].l == t[u].r ) return t[u].val;
	down(u);
	return qval( p<=t[ls].r?ls:rs ,p);
}
U qsum(int u,int l,int r) {
	if( l > r ) return 0;
	if( l <= t[u].l && t[u].r <= r ) return t[u].sum;
	down(u);
	U res = 0;
	if( l <= t[ls].r ) res = qsum(ls,l,r);
	if( t[rs].l <= r ) res += qsum(rs,l,r);
	return res;
}
#undef ls
#undef rs

signed main() {
	read(n,m);
	For(i,2,n) read(fa[i]), to[fa[i]].pb(i);
	dfs1(1), dfs2(1,1), build(1,1,n);
	s[1].insert(1), addsiz(1,1,n);
	while( m-- ) {
		int op,u,v,l,r; U x,sizu; read(op,u); l = dfn[u], r = dfn[u]+siz[u]-1;
		switch(op) {
			case 1: write(qval(1,dfn[belong(u)])+bit.query(l,l)); break;
			case 2: read(x); addval(1,l,l,x); break;
			case 3:
				write(qval(1,dfn[belong(u)])*(siz[u]-qsiz(1,l+1,r)) +
					  qsum(1,l+1,r) + bit.query(l,r)); 
				break;
			case 4: read(x); addval(1,l,r,x); break;
			case 5:
				v = belong(u), s[top[u]].insert(dep[u]);
				sizu = siz[u]-qsiz(1,l+1,r);
				covval(1,l,qval(1,dfn[v])), addsiz(1,l,sizu);
				addsiz(1,dfn[v],-sizu);
				break;
			default:
				v = belong(fa[u]), s[top[u]].erase(dep[u]);
				sizu = siz[u]-qsiz(1,l+1,r);
				U valu = qval(1,l), valv = qval(1,dfn[v]);
				covval(1,l,0), addsiz(1,l,-sizu);
				addsiz(1,dfn[v],sizu);
				bit.modify(l,r,valu-valv), addval(1,l,r,-(valu-valv));
		}
	}
	return iocl();
}
T4

先鸽了

标签:head,数树,int,siz,son,mm,ckw,20210823,mod
来源: https://www.cnblogs.com/401rk8/p/noip0825.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有