首页 > 其他分享 >Codeforces Round 975 (Div. 2) 题解:D、E

Codeforces Round 975 (Div. 2) 题解:D、E

时间:2024-09-28 16:01:47浏览次数:7  
标签:975 子树 const int 题解 ll 50 Div define

第一次进前50,上分最爽的一次

D. Speedbreaker

对\(a\)按照时间升序排序,不难发现,对于升序排序后的数组,当我们搜到时间\(t\)时,记录已经搜过的时间对应原城市编号最小值为\(l\),最大值为\(r\),则我们一定要在\(a_t\)时间之前走过所有\([l,r]\)之间的城市。

则若\(r-l+1 > a_t\)则无解,因为不能在\(t\)内走过\([l,r]\)之间的所有城市

否则,可能的合法城市只会出现在\([r-t+1,l+t-1]\)之间

总的合法城市为所有合法城市的并集,此处可以用前缀和处理

时间复杂度\(O(nlogn)\)

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 1e6+50;
const int M = 2e5+50;
const ll mod = 1e9+7;
#define pll pair<ll,ll>
#define pii pair<int,int>
#define eps 1e-8
const ll inf = 1e18;
#define ls (p<<1)
#define rs ((p<<1)+1)
#define mi (l+r)/2
const double DINF = 12345678910 , PI = acos(-1);
int mx[] = {0,0,1,-1} , my[] = {1,-1,0,0};
void YES(){
	cout << "YES\n";
	return;
}
void NO(){
	cout << "NO\n";
	return;
}

int n;
pii a[N];
int pre[N];

void solve(){
	cin >> n;
	for (int i = 1 ; i <= n ; ++i){
		pre[i] = 0;
		cin >> a[i].first;
		a[i].second = i;
	}
	sort(a+1,a+1+n);
	int l = n+1 , r = 0;
	for (int i = 1 ; i <= n ; ++i){
		l = min(a[i].second,l);
		r = max(a[i].second , r);
		if (r-l+1 > a[i].first){
			cout << "0\n";
			return;
		}
		int left = r-a[i].first+1  , right = l+a[i].first-1;
		left = max(left , 1);
		right = min(right , n);
		pre[left]++;
		pre[right+1]--;
	}

	int tmp = 0 , ans = 0;
	for (int i = 1 ; i <= n ; ++i){
		// cout << pre[i] << " ";
		tmp += pre[i];
		ans += (tmp == n);
	}
	cout << ans << "\n";
}
	

int main(){
	ios::sync_with_stdio(0) , cin.tie(0);
	// init();
	int t; 
	cin >> t;
	for (int i = 1 ; i <= t ; ++i){
		solve();
	}
	// solve();
}

E. Tree Pruning

一个结论:若答案为\(d\),则我们要将深度大于 \(d\) 的所有节点砍掉,对于最深深度小于 \(d\) 的子树砍掉

记答案为\(d\)时,需要砍掉 \(a_d\) 个节点,子树\(v\)的大小为 \(sz_v\)

考虑在树上,当我们搜索到节点 \(u\) ,若 \(u\) 目前搜索过的子树最深深度为\(d_u\),则当搜索完其一棵新的子树,并对当前节点进行更新,
若子树最深深度 \(d_v \leq d_u\),则对于答案在区间 \([d_v+1,d_u]\) 之间时,需要砍掉这整棵子树,即 $a_{d_v+1},a_{d_v+2}...,a_{d_u} $需要加上 \(sz_v\)
若 \(d_v > d_u\) ,则对于答案在区间 \([d_u+1,d_v]\) 之间时,需要砍掉之前搜索过的子树,即加上已搜索的子树大小 \(sz_u\)

当一个节点\(u\)搜索结束后,得到对于\(a_d\)的贡献为其所有子树大小之和

容易发现,所有修改都是连续区间,可以使用前缀和维护

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 5e5+50;
const int M = 2e5+50;
const ll mod = 1e9+7;
#define pll pair<ll,ll>
#define pii pair<int,int>
#define eps 1e-8
const ll inf = 1e18;
#define ls (p<<1)
#define rs ((p<<1)+1)
#define mi (l+r)/2
const double DINF = 12345678910 , PI = acos(-1);
int mx[] = {0,0,1,-1} , my[] = {1,-1,0,0};
void YES(){
	cout << "YES\n";
	return;
}
void NO(){
	cout << "NO\n";
	return;
}

int head[N];
int tot;
bool vi[N];

struct edge
{
	int to , nxt , w;
}e[N*2];

void add(int u , int v , ll w = 0){
	e[++tot] = (edge){v , head[u] , w};
	head[u] = tot;
}

int n;
int pre[N];
int dep[N];
int sz[N];
int depest[N];
int maxn = 0;

void dfs(int u , int fa){
	bool fg = 0;
	sz[u] = 0;
	dep[u] = dep[fa]+1;
	maxn = max(maxn , dep[u]);
	depest[u] = dep[u];
	for (int i = head[u] ; i ; i = e[i].nxt){
		int v = e[i].to;
		if (v == fa)	continue;
		fg = 1;
		dfs(v,u);
		if (depest[u] != dep[u]){
			if (depest[u] < depest[v]){
				pre[depest[u]+1] += sz[u];
				pre[depest[v]+1] -= sz[u];
				depest[u] = depest[v];
			}
			else{
				pre[depest[v]+1] += sz[v];
				pre[depest[u]+1] -= sz[v];
			}

		}
		else{
			depest[u] = depest[v];
		}
		sz[u] += sz[v];
		
	}
	pre[dep[u]] += sz[u];
	pre[dep[u]+1] -= sz[u];
	sz[u]++;
}

void solve(){
	cin >> n;
	tot = 0;
	maxn = 0;
	for (int i = 1 ; i <= n ; ++i){
		head[i] = 0;
		pre[i] = 0;
	}
	for (int i = 1 ; i < n ; ++i){
		int u , v;
		cin >> u >> v;
		add(u,v) , add(v,u);
	}
	dfs(1,0);
	int minn = n*10 , tmp = 0;
	for (int i = 1 ; i <= maxn ; ++i){
		
		tmp += pre[i];
		// cout << i << "*" << tmp << "\n";
		minn = min(minn,tmp);
	}
	cout << minn << "\n";
}
	

int main(){
	ios::sync_with_stdio(0) , cin.tie(0);
	// init();
	int t; 
	cin >> t;
	for (int i = 1 ; i <= t ; ++i){
		solve();
	}
	// solve();
}

标签:975,子树,const,int,题解,ll,50,Div,define
From: https://www.cnblogs.com/happyalg/p/18438067

相关文章

  • [USACO22DEC] Breakdown P 题解
    T1[USACO22DEC]BreakdownP比较显然的一点是,一次加一条边/一次删一条边,显然转化,这是显然的一条套路。这题的\(K\le8\),很有意思的数据范围,然后调用我们聪明的人类大脑得知需要用到折半搜索。所以我们只考虑\(K\le4\)的情况,令\(\mathit{st}\)表示折半搜索中考虑的起点。维......
  • [NOIP2017 提高组] 奶酪 题解
    题目背景NOIP2017提高组D2T1题目描述现有一块大奶酪,它的高度为 h,它的长度和宽度我们可以认为是无限大的,奶酪中间有许多半径相同的球形空洞。我们可以在这块奶酪中建立空间坐标系,在坐标系中,奶酪的下表面为 z=0,奶酪的上表面为 z=h。现在,奶酪的下表面有一只小老鼠Jerry,......
  • 洛谷P1827 [USACO3.4] 美国血统 题解
    上题目:题目描述农夫约翰非常认真地对待他的奶牛们的血统。然而他不是一个真正优秀的记帐员。他把他的奶牛们的家谱作成二叉树,并且把二叉树以更线性的“树的中序遍历”和“树的前序遍历”的符号加以记录而不是用图形的方法。你的任务是在被给予奶牛家谱的“树中序遍历”和......
  • 洛谷P1162 填涂颜色题解
    老规矩上题目:题目描述由数字 00 组成的方阵中,有一任意形状的由数字 11 构成的闭合圈。现要求把闭合圈内的所有空间都填写成 22。例如:6×66×6 的方阵(n=6n=6),涂色前和涂色后的方阵如下:如果从某个 00 出发,只向上下左右 44 个方向移动且仅经过其他 00 的情况下,无法......
  • 题解 HZOJ 284 超市卖货 C/C++
    题目传送门:超市卖货-题目-OnlineJudge(haizeix.com)https://oj.haizeix.com/problem/284思路:每次寻找价格最高的商品,并尝试卖掉它:寻找未卖出商品的日期,优先锁定其保质期最后一天,若该日期已卖出则继续向前寻找能找到未卖出商品的日期时,收入增加,标记该日期代码实现:为......
  • Echarts图表知识点汇总及请求django服务器后端跨域问题解决
    1.引入echartsvue3中通过npm引入:npminstallecharts--saveimport*asechartsfrom'echarts';//基于准备好的dom,初始化echarts实例varmyChart=echarts.init(document.getElementById('main'));//绘制图表myChart.setOption({title:{text:'ECha......
  • P9019 [USACO23JAN] Tractor Paths P 题解
    P9019[USACO23JAN]TractorPathsP题解难度其实绝对不止蓝题。先考虑第一问。维护任意两点之间的最短路是困难的,难以dp或是采取其它方法解决。难以算最短路就转换思路,考虑从\(x\)走\(p\)步能走到哪。考虑到这个东西是有单调性的,也就是说对于\(x<y<z\),从\(x\)能走到......
  • Codeforces Round 944 (Div. 4) A~G题解
    A\(min\)函数和\(max\)函数的使用,按照格式输出即可。#include<bits/stdc++.h>usingnamespacestd;typedeflonglongLL;typedefpair<int,int>PII;voidsolve(){intx,y;cin>>x>>y;cout<<min(x,y)<<'......
  • Codeforces Round 973题解(E)
    E.PrefixGCD假设我们从一个空集合\(b\)开始,不断从\(a\)数组中选择一个元素添加到\(b\)集合的尾部,当把\(a\)数组的元素全部添加到\(b\)中后,得到的\(b\)即为所求的rearrange后的\(a\)。结论1:每次选择使得其和当前\(b\)中所有元素的最大公约数最小的那个\(a_i\)加入到\(b\)的末......
  • ZZJC新生训练赛第一场题解
    先给出比赛链接:https://ac.nowcoder.com/acm/contest/91452下面说一下难度分层:(同一难度下按字典序排序)Easy(简单):B,FMedium(中等):A,E,HHard(困难):C,GAnti-AK(防AK):D,Icin.tie(nullptr)->sync_with_stdio(false);//加速输入输出的A游游的整数翻转将所......