「csp模拟」模拟测试14
T1 : 虎
题解
- 贪心的思想,30分的数据给了一个提示,子树中尽可能的两两配对,如果有剩余就往上,那设关于的这一个看看能不能往上传递,于是\(\text{dfs}\)一边就好了
code
#include <bits/stdc++.h>
using namespace std;
inline int read() {
int k = 0, f = 1; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
for (; isdigit(ch); ch = getchar()) k = k * 10 + ch - '0';
return k * f;
}
const int maxn = 4e6 + 100;
struct node { int to, next, col, lim; } e[maxn];
int head[maxn], ecnt = 0;
void add(int u, int v, int w, int x) { e[++ecnt] = (node){v, head[u], w, x}; head[u] = ecnt; }
int cnt = 0;
int dfs(int u, int f, int col, int lim) {
int tmp = 0;
for (int i = head[u]; i; i = e[i].next) {
int v = e[i].to;
if (v == f) continue;
int flag = dfs(v, u, e[i].col, e[i].lim); // 看看子树能否有剩余
if ((e[i].col == 1 && e[i].lim == 1) || (!flag && e[i].lim == 0)) continue; // 如果不需要更改,直接跳过
if (tmp) tmp = 0, cnt ++; // 进行配对,如果tmp有值,说明有一对配对成功,cnt ++
else tmp = 1; //没有找到配对的单独一个
}
if (tmp == 0) return 0; // 如果全部成功配对, return 0
if (col == 1 && lim == 1) { cnt++; return 0; } // 如果u到f不用更改就直接cnt++
return 1; // 否则就把这条边传递上去与上一个连起来
}
int main() {
#ifdef debug
//freopen("in", "r", stdin);
#else
freopen("tiger.in", "r", stdin); freopen("tiger.out", "w", stdout);
#endif
int n = read();
int flag = 0, num = 0;
for (int i = 2; i <= n; i++) {
int x = read(), y = read(), z = read();
if (x != 1) flag = 1;
if (y == 0 && z == 1) num ++;
add(i, x, y, z), add(x, i, y, z);
}
if (!flag) return printf("%d\n", (num + 1) / 2), 0;
dfs(1, 0, 1, 1);
printf("%d\n", cnt);
}
T2 : 陶陶摘苹果
题解
法一
首先可以预处理出每个点到结尾的上升序列的长度以及到每个点的答案,然后st表维护区间最大值,每次修改一个位置的pos可以先把到pos - 1
的贡献加上,然后判断这个点是否能产生贡献,如果可以的话,就更新答案,并更新最大值,然后再二分查找后面第一个比他大的数字,在加上这个数字到结尾的上升序列长度即可。
code
#include <bits/stdc++.h>
using namespace std;
#define max(a, b) (a) > (b) ? (a) : (b)
#define print(start, end) copy(start, end, ostream_iterator<int>(cout, " ")), cout << endl;
inline int read() {
int k = 0, f = 1; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
for (; isdigit(ch); ch = getchar()) k = k * 10 + ch - '0';
return k * f;
}
const int maxn = 1e5 + 10;
int f[maxn][22], logn[maxn];
int h[maxn], jl[maxn], jl2[maxn];
int n, m;
void st_prework() {
for (register int i = 1; i <= n; i++) f[i][0] = h[i];
register int t = logn[n] + 1;
for (register int j = 1; j <= t; j++) {
for (register int i = 1; i <= n - (1 << j) + 1; i++)
f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
}
}
int st_query(int l, int r) {
register int k = logn[r - l + 1];
return max(f[l][k], f[r - (1 << k) + 1][k]);
}
int main() {
#ifdef debug
// freopen("in", "r", stdin);
#else
freopen("taopapp.in", "r", stdin);
freopen("taopapp.out", "w", stdout);
#endif
n = read(), m = read();
for (register int i = 1; i <= n; i++) h[i] = read();
for (register int i = 2; i <= n; i++) logn[i] = logn[i / 2] + 1;
st_prework();
register int ans = 0, maxx = 0;
maxx = h[1], jl[1] = 1;
for(register int i = 2; i <= n; ++i) {
if(h[i] > maxx) {
jl[i] = jl[i - 1] + 1;
maxx = h[i];
}
else jl[i] = jl[i - 1];
}
jl2[n] = 1;
for(register int i = n - 1, x; i >= 1; --i) {
x = h[i];
register int l = i + 1, r = n, mid = 0;
while(l <= r) {
mid = (l + r) / 2;
if(st_query(i + 1, mid) > x) r = mid - 1;
else l = mid + 1;
}
jl2[i] = jl2[l] + 1;
}
// coutprint(jl + 1, jl + n + 1);
while (m--) {
int pos = read(), val = read(), tmp = h[pos], maxx = st_query(1, pos - 1), ans = 0;
h[pos] = val;
ans += jl[pos - 1];
if (val > maxx) ans++, maxx = val;
// cout << st_query(pos + 1, n) << endl;
int l = pos + 1, r = n, mid;
while(l <= r) {
mid = (l + r) / 2;
if(st_query(pos + 1, mid) > maxx) r = mid - 1;
else l = mid + 1;
}
ans += jl2[l];
printf("%d\n", ans);
h[pos] = tmp;
}
}
法二
线段树维护单调栈
code
#include <bits/stdc++.h>
using namespace std;
inline int read() {
int k = 0, f = 1; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
for (; isdigit(ch); ch = getchar()) k = k * 10 + ch - '0';
return k * f;
}
const int maxn = 4e5 + 100;
int h[maxn];
int n, m;
struct node { int l, r, maxx, len; } t[maxn];
#define tl t[rt].l
#define tr t[rt].r
#define ls (rt << 1)
#define rs (rt << 1 | 1)
int calc(int rt, int val) {
if (tl == tr) return t[rt].maxx > val;
if (t[ls].maxx > val) return calc(ls, val) + t[rs].len;
else return calc(rs, val);
}
void pushup(int rt) {
t[rt].maxx = max(t[ls].maxx, t[rs].maxx);
t[rs].len = calc(rs, t[ls].maxx);
}
void build(int rt, int l, int r) {
tl = l, tr = r;
if (l == r) return t[rt].maxx = h[l], void();
int mid = (l + r) >> 1;
build(ls, l, mid), build(rs, mid + 1, r);
pushup(rt);
}
void modify(int rt, int pos) {
if (tl == tr) return t[rt].maxx = h[pos], void();
int mid = (tl + tr) >> 1;
if (pos <= mid) modify(ls, pos);
else modify(rs, pos);
pushup(rt);
}
int main() {
#ifdef debug
#else
freopen("taopapp.in", "r", stdin);
freopen("taopapp.out", "w", stdout);
#endif
n = read(), m = read();
for (int i = 1; i <= n; i++) h[i] = read();
build(1, 1, n);
while (m--) {
int pos = read(), val = read(), tmp = h[pos];
h[pos] = val;
modify(1, pos);
printf("%d\n", calc(1, -1));
h[pos] = tmp;
modify(1, pos);
}
return 0;
}
T3 : 开心的金明
T4 : 笨小猴
- 构造 : 以a的大小排序,然后对于每相邻的两个去较大的那个,最后在选上多的那个,即可。
- 当然,random_shuffle大法好,只是开小了数组就不那么好了。。。
#include <bits/stdc++.h>
using namespace std;
inline int read() {
int k = 0, f = 1; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
for (; isdigit(ch); ch = getchar()) k = k * 10 + ch - '0';
return k * f;
}
#define int long long
const int maxn = 2e5 + 100;
struct node { int a, b, id; } a[maxn];
signed main() {
freopen("grandmaster.in", "r", stdin);
freopen("grandmaster.out", "w", stdout);
register int n = read(), suma = 0, sumb = 0;
for (int i = 1; i <= 2 * n + 1; i++) {
a[i].a = read(), a[i].b = read(), a[i].id = i;
suma += a[i].a, sumb += a[i].b;
}
// suma = suma >> 1, sumb = sumb >> 1;
register int cura = 0, curb = 0;
while (1) {
srand(time(0));
cura = curb = 0;
random_shuffle(a + 1, a + 2 * n + 2);
for (register int i = 1; i <= n + 1; i++) cura += a[i].a, curb += a[i].b;
if (2 * cura > suma && 2 * curb > sumb) {
for (register int i = 1; i <= n + 1; i++) printf("%lld\n", a[i + 1].id);
return 0;
}
}
return 0;
}
T5:楼房重建
#include <bits/stdc++.h>
using namespace std;
inline int read() {
int k = 0, f = 1; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
for (; isdigit(ch); ch = getchar()) k = k * 10 + ch - '0';
return k * f;
}
const int maxn = 4e5 + 100;
double h[maxn];
struct node { int l, r, len; double maxx;} t[maxn];
#define tl t[rt].l
#define tr t[rt].r
#define ls (rt << 1)
#define rs (rt << 1 | 1)
int calc(int rt, double val) {
if (tl == tr) return t[rt].maxx > val;
if (t[ls].maxx > val) return calc(ls, val) + t[rs].len;
else return calc(rs, val);
}
void pushup(int rt) {
t[rt].maxx = max(t[ls].maxx, t[rs].maxx);
t[rs].len = calc(rs, t[ls].maxx);
}
void build(int rt, int l, int r) {
t[rt].l = l, t[rt].r = r;
if (l == r) return;
int mid = (l + r) >> 1;
build(ls, l, mid), build(rs, mid + 1, r);
pushup(rt);
}
void modify(int rt, int pos) {
if (tl == tr) return t[rt].maxx = h[pos], void();
int mid = (tl + tr) >> 1;
if (pos <= mid) modify(ls, pos);
else modify(rs, pos);
pushup(rt);
}
int main() {
int n = read(), m = read();
build(1, 1, n);
// cout << calc(1, -1) << endl;
while (m--) {
int x = read(), y = read();
h[x] = 1.0 * y / x;
// printf("h[x] = %lf\n", h[x]);
modify(1, x);
printf("%d\n", calc(1, 0));
}
}