ICode9

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

2021.10.16CSP模拟赛22 赛后总结

2021-10-18 19:01:49  阅读:101  来源: 互联网

标签:ch 2021.10 22 fa int ll 16CSP read include


A. 区间

这题似乎用 \(ST\) 表,单调栈等各种方法都可以过。

我用的是无脑线段树(智商不够,数据结构来凑)。

简单来说,维护一下区间最小值及其位置即可,然后递归输出。

直接贴代码吧。

这个 \(pushup\) 好像不能写三目运算符(不知道为什么),大样例一直过不去,然后调了半天 \(QwQ\)。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define ls rt << 1
#define rs rt << 1 | 1

using namespace std;

const int N = 2e5 + 10;
int n;
int a[N], mins[N << 2], pos[N << 2];

inline void pushup(int rt){
	if(mins[ls] <= mins[rs]) pos[rt] = pos[ls], mins[rt] = mins[ls];
	else pos[rt] = pos[rs], mins[rt] = mins[rs];
}

inline void build(int l, int r, int rt){
	if(l == r){
		mins[rt] = a[l];
		pos[rt] = l;
		return;
	}
	int mid = (l + r) >> 1;
	build(l, mid, ls);
	build(mid + 1, r, rs);
	pushup(rt);
}

inline int query(int L, int R, int l, int r, int rt){
	if(l > R || r < L) return 0;
	if(L <= l && r <= R)
		return pos[rt];
	int mid = (l + r) >> 1;
	int res = 0;
	if(L <= mid) res = query(L, R, l, mid, ls);
	if(R > mid){
		int id = query(L, R, mid + 1, r, rs);
		if(a[id] < a[res]) res = id;
	}
	return res;
}

struct node{
	int l, r;
}ans[N];
int cnt;

inline void dfs(int l, int r, int tmp){
	if(l > r) return;
	int id = query(l, r, 1, n, 1);
	int res = a[id] - tmp, d = 0;
	while(res > 0){
		ans[++cnt].l = l, ans[cnt].r = r;
		res--, d++;
	}
	dfs(l, id - 1, tmp + d), dfs(id + 1, r, tmp + d);
}

int main(){
	scanf("%d", &n);
	for(int i = 1; i <= n; i++)
		scanf("%d", &a[i]);
	a[0] = 1e9;
	memset(mins, 0x3f, sizeof(mins));
	build(1, n, 1);
	dfs(1, n, 0);
	printf("%d\n", cnt);
	for(int i = 1; i <= cnt; i++)
		printf("%d %d\n", ans[i].l, ans[i].r);
	return 0;
}

B. 树

事实上我并不是很会算期望,所以就算给我 \(n \leq 10\) 数据的我也做不出来 \(QwQ\)。

考场上当然就直接弃了。

后来听学长讲,发现是一波大力推式子。

由于输入的是一棵树,所以从 \(u\) 到 \(v\) 的路径是先网上走到 \(lca(u, v)\),再往下走到 \(v\)。

所以先推出来从 \(x\) 节点走到 \(fa_x\) 的期望,然后推从 \(fa_x\) 走到 \(x\) 的期望(懒得打了,可以去看别人的题解)。就可以求解了。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#define ll long long

using namespace std;

inline int read(){
	int x = 0;
	char ch = getchar();
	while(ch < '0' || ch > '9') ch = getchar();
	while(ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
	return x;
}

const int mod = 1e9 + 7;
const int N = 1e5 + 10;
int n, m;
struct node{
	int v, nxt;
}edge[N << 1];
int head[N], tot;
int ans;
int fa[N][20], dep[N];
ll f[N],g[N];

inline void add(int x, int y){
	edge[++tot] = (node){y, head[x]};
	head[x] = tot;
}

inline void dfs1(int x, int p){
	fa[x][0] = p, dep[x] = dep[p] + 1;
	for(int i = 1; i <= 20; i++)
		fa[x][i] = fa[fa[x][i - 1]][i - 1];
	f[x] = 1;
	for(int i = head[x]; i; i = edge[i].nxt){
		int y = edge[i].v;
		if(y == p) continue;
		dfs1(y, x);
		f[x] = (f[x] + f[y] + 1) % mod;
	}
}

inline void dfs2(int x, int p){
	for(int i = head[x]; i; i = edge[i].nxt){
		int y = edge[i].v;
		if(y == p) continue;
		g[y] = (g[x] + f[x] - f[y]) % mod;
		dfs2(y, x);
	}
}

inline void dfs3(int x, int p){
	f[x] += f[p], g[x] += g[p];
	for(int i = head[x]; i; i = edge[i].nxt)
		if(edge[i].v != p)
			dfs3(edge[i].v, x);
}

inline int lca(int a, int b){
	if(dep[a] < dep[b]) swap(a, b);
	for(int i = 20; i >= 0; i--)
		if(dep[fa[a][i]] >= dep[b]) a = fa[a][i];
	if(a == b) return a;
	for(int i = 20; i >= 0; i--)
		if(fa[a][i] != fa[b][i])
			a = fa[a][i], b = fa[b][i];
	return fa[a][0];
}

signed main(){
	n = read(), m = read();
	for(int i = 1; i < n; i++){
		int u = read(), v = read();
		add(u, v), add(v, u);
	}
	dfs1(1, 0);
	f[1]--;
	dfs2(1, 0), dfs3(1, 0);
	while(m--){
		int u = read(), v = read();
		int k = lca(u, v);
		// cout <<" dd " <<k << endl;
		printf("%lld\n", ((f[u] - f[k] + g[v] - g[k]) % mod + mod) % mod);
	}
	return 0;
}

C. 做运动

巨水的一道题,但是高一学生们全都写的二分 + \(dij\)(默契十足),复杂度 \(O(nlog_n^2)\),然后全都被卡到 10 ~ 30 分不等……

然鹅正解是并查集 + \(dij\),复杂度 \(O(nlogn)\)。

先按温度排序,然后不停加边,当起点和终点在同一集合中时,最大温度就是那条边的温度,然后把所有合法的边全都加进去,跑个最短路即可。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cstring>
#define INF 1e18
#define ll long long

using namespace std;

inline ll read(){
	ll x = 0;
	char ch = getchar();
	while(ch < '0' || ch > '9') ch = getchar();
	while(ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
	return x;
}

const ll N = 5e5 + 10;
const ll M = 1e6 + 10;
ll n, m;
struct node{
	ll u, v, t, c, nxt;
	bool operator < (const node &b) const{
		return t < b.t;
	}
}edge[M << 1], e[M];
ll head[N], tot;
ll temp[M];
ll st, en;
ll dis[N], f[N];
struct Que{
	ll x, dis;
	bool operator < (const Que &b) const{
		return dis > b.dis;
	}
};

inline void add(ll x, ll y, ll c){
	edge[++tot].v = y, edge[tot].c = c, edge[tot].nxt = head[x];
	head[x] = tot;
}

inline void dijkstra(){
	priority_queue <Que> q;
	q.push((Que){st, 0});
	for(int i = 1; i <= n; i++) dis[i] = INF;
	dis[st] = 0;
	while(!q.empty()){
		Que now = q.top();
		q.pop();
		ll x = now.x;
		if(dis[x] < now.dis) continue;
		for(ll i = head[x]; i; i = edge[i].nxt){
			ll y = edge[i].v;
			if(dis[y] > dis[x] + edge[i].c){
				dis[y] = dis[x] + edge[i].c;
				q.push((Que){y, dis[y]});
			}
		}
	}
}

inline int find(int x){
	return f[x] == x ? x : f[x] = find(f[x]);
}

signed main(){
	n = read(), m = read();
	for(ll i = 1; i <= m; i++){
		e[i].u = read(), e[i].v = read(), e[i].t = read(), e[i].c = read();
	}
	st = read(), en = read();
	for(int i = 1; i <= n; i++)
		f[i] = i;
	sort(e + 1, e + 1 + m);
	ll mint, pos;
	for(int i = 1; i <= m; i++){
		int fu = find(e[i].u), fv = find(e[i].v);
		if(fu != fv) f[fu] = fv;
		add(e[i].u, e[i].v, e[i].c * e[i].t), add(e[i].v, e[i].u, e[i].c * e[i].t);
		if(find(st) == find(en)){
			mint = e[i].t, pos = i;
			break;
		}
	}
	for(int i = pos + 1; i <= m; i++){
		if(e[i].t != e[pos].t) break;
		add(e[i].u, e[i].v, e[i].c * e[i].t), add(e[i].v, e[i].u, e[i].c * e[i].t);
	}
	dijkstra();
	printf("%lld %lld\n", mint, dis[en]);
	return 0;
}

D. 手机信号

考场上打 \(O(n^2)\) 暴力,结果没注意写了个 \(c * c\) 直接 \(1e36\) 爆 \(long\ long\) 了,然后 30pts 都没有拿到 \(QwQ\)。

正解似乎是 \(set\) + 乱搞。

然鹅还不太会,先咕了,以后会了在补吧。

标签:ch,2021.10,22,fa,int,ll,16CSP,read,include
来源: https://www.cnblogs.com/xixike/p/15421858.html

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

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

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

ICode9版权所有