作业介绍

// 可以理解为从 某个点 u 出发,然后每次只能往上走
// 寻找最长的序列的长度,使得经过的 w[i] 的和 小于等于  c[u]
// 走的时候可以倍增走,快速走, 最后的结果就是 深度的差值
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
#define int long long
vector<int> e[N];
int n, sum[N], w[N], c[N];
int f[N][25];

int dep[N];

void dfs(int u, int fa) {
	sum[u] = sum[fa] + w[u]; //类似前缀和
	dep[u] = dep[fa] + 1;
	f[u][0] = fa;
	for (int i = 1; i < 20; i++)
		f[u][i] = f[f[u][i - 1]][i - 1];
	for (auto v : e[u]) {
		dfs(v, u);
	}

}

signed main() {
	cin >> n;
	for (int i = 2; i <= n; i++) {
		int x;
		cin >> x;
		e[x].push_back(i);  // 记录他的子节点
	}
	for (int i = 1; i <= n; i++)
		cin >> w[i];
	for (int i = 1; i <= n; i++)
		cin >> c[i];
	dfs(1, 0);
	for (int i = 1; i <= n; i++) {
		int u = i;
		for (int j = 19; j >= 0; j--) {
			if (f[u][j] == 0) continue;
			// 求区间和
			// 计算的区间和是 从 i 到 f[u][j] 之间的和
			if (sum[i] - sum[f[u][j]] + w[f[u][j]] <= c[i])
				u = f[u][j];
		}
		cout << dep[i] - dep[u] + 1 << " ";
	}
	return 0;
}
// 有很多的等差数列
// 每个位置上有一个人,最多只会有一个位置是奇数
// 求这个位置,这个位置的人数
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
#define int long long
int n, s[N], e[N], d[N];
int T;
int ans, cnt;

int get(int x) {
	int sum = 0;
	for (int i = 1 ; i <= n; i++) {
		if (x < s[i])
			continue;
		sum += (min(x, e[i]) - s[i]) / d[i] + 1;
	}
	return sum;
}

signed main() {
	cin >> T;
	while (T--) {
		cin >> n;
		int sum = 0;
		int maxx = 0;
		for (int i = 1 ; i <= n; i++) {
			cin >> s[i] >> e[i] >> d[i];
			sum += (e[i] - s[i]) / d[i] + 1;
			maxx = max(maxx, e[i]);
		}
		if (sum % 2 == 0) {
			cout << "Poor QIN Teng:( \n";
			continue;
		} else {
			int l = 0;
			int t  = 1;  // 第一次的区间长度
			while (t) { // 最后结束变成一个点
				// get(x) 求的是 [1,x] 的和
				if ( l + t <= maxx && get(l + t) % 2 == 0 ) {
					l += t;
					t = t * 2;
				} else
					t = t / 2;
			}
			// 找到了奇数的位置
			ans  = l + 1, cnt = 0;
			// 计算这个位置有多少个人
			for (int i = 1; i <= n; i++) {
				if (s[i] <= ans && ans <= e[i] && (ans - s[i]) % d[i] == 0)
					cnt++;
			}
			cout << ans << " " << cnt << endl;
		}
	}
	return 0;
}

// last[value]表示盈利值 value 最近出现的位置
// st[i]表示第i个数为结尾的最长完美序列的起始位置
// st[i] = max(st[i-1] , last[a[i]]+1)
// f[i] 表示以第 i 个数结尾的最长完美序列的长度
// f[i] = i - st[i]+1
// st值为非递减序列,对于询问区间 [li,ri]
// 该区间的 st 值可能会出现:左边一部分的 st 值不在区间内,即小于 li
// 右边一部分的 st 值大于等于 li
// st 值具有单调性,可以通过二分得到, 假设这个位置为 mid
// 则 st[li...mi-1] < li, st[mi...ri]>li
// 所以最后的结果为:左边部分的结果为 mid - li
// 右边部分的结果为:[mid, ri] 的最大值,用 ST 算法来求

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+10;
const int M = 1e6+10;
int last[M << 1], mx[N][20];
int f[N], st[N], lg[N];
int n, m, l, r, x;
int find(int l1, int r1) {
	// 当 mi 等于 l1 时,左边部分的最大值为0,不用考虑
	if (st[l1] == l1) return l1;
	// 当 mi 小于 l1 时,不存在左边部分,不用考虑
	if (st[r1] < l1) return r1 + 1;
	int l = l1, r = r1;
	while (l <= r) {
		int mid = l + r >> 1;
		if (st[mid] < l1) l = mid + 1;
		else r  = mid - 1;
	}
	return l;
}

int query(int l, int r) {
	int x = lg[r - l + 1];
	return max(mx[l][x], mx[r - (1 << x) +1][x]);
}

int main() {
	scanf("%d%d", &n, &m);
	lg[0] = -1;
	for (int i = 1; i <= n; i++) {
		scanf("%d", &x);
		// x+M  拒绝负数下标
		st[i] = max(st[i - 1], last[x + M] + 1);
		f[i] = i - st[i] + 1;
		lg[i] = lg[i / 2] + 1;
		last[x + M] = i;
	}
	for (int i = 1; i <= n; i++)
		mx[i][0] = f[i];
	for (int j = 1; j <= lg[n]; j++) {
		for (int i = 1; i + (1 << j - 1) <= n; i++) {
			mx[i][j] = max(mx[i][j - 1], mx[i + (1 << j - 1)][j - 1]);
		}
	}
	while (m--) {
		scanf("%d%d", &l, &r);
		++l, ++r;
		int mid = find(l, r), ans = 0, tmp;
		if (mid > l) ans = mid - l;
		if (mid <= r) {
			tmp = query(mid, r);
			ans = max(ans, tmp);
		}
		printf("%d\n", ans);
	}
	return 0;
}
//st[i][j] 从i位置开始,往后2^j个位置的最大值,包含i位置

//st[i][j] = max(a[i] , a[i+1] ... a[i+2^j-1])
//st[i][0] = a[i]
//2^j = 2^(j-1)  +  2^(j-1)
//
//
//st[i][j] = max(st[i][j-1] , st[i+(1<<j-1)][j-1])
//
//st[i][j] = max(a[i] , a[i+1] ... a[i+2^j-1])
//
//st[i][j-1] = max(a[i] , a[i+1] ... a[i+2^(j-1)-1])
//st[i+(1<<j-1)][j-1] = max(a[i+ 2^(j-1)] ....a[i+2^j-1])
//
//for(int i=1;i<=n;i++)
//	st[i][0] =a[i]
//for(int j= 1;(1<<j)<=n;j++){
//	for(int i=1;i+(1<<j)-1<=n;i++)
//		st[i][j] = max(st[i][j-1] , st[i+(1<<j-1)][j-1]);
//}
//
//st[i][j]  从 i 开始往后 2^j 个数字的最大值
//求 [l,r] 区间的最大值 ???
//
//len = r - l+1
//第一个区间是从 l 开始往后走 len , 最好的结果是等于 len, 小于等于的最大
//第二个区间是 r - len 开始走 len
//2^j = len, j 等于 log_2(len)
//
//l,r的最大值 max( st[l][log(len)] , st[r -(1<<log2(len))+1][log(len)])
//

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n, m, a[N], st[N][20];
int lg[N];

void init() {
	lg[1] = 0; // 2^0 =1
	for (int i = 2; i <= n; i++)
		lg[i] = lg[i / 2] + 1;
	for (int i = 1; i <= n; i++)
		st[i][0] = a[i];
	for (int j = 1; j <= lg[n]; j++) {
		for (int i = 1; i + (1 << j - 1) <= n; i++)
			st[i][j] = max(st[i][j - 1], st[i + (1 << j - 1)][j - 1]);
	}
}

int query(int l, int r) {
	int len  = r - l + 1;
	int res = max(st[l][lg[len]], st[r - (1 << lg[len]) + 1][lg[len]]);
	return res;
}

int main() {
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
		cin >> a[i];
	init();
	while (m--) {
		int l, r;
		cin >> l >> r;
		cout << query(l, r) << '\n';
	}
	return 0;
}
状态
已结束
题目
15
开始时间
2026-5-1 0:00
截止时间
2026-5-31 23:59
可延期
24 小时