kuangbin专题
1. 敌兵布阵 HDU - 1166
难度: ★【究极入门题,纯当是检验板子】
题意: 中文题面,不再赘述
题解: 参考线段树&树状数组算法,有板子就是直接AC。
因为是回头刚整理线段树,所以搞了个不一定全面当时非常长的模板,凑合着用
#include<bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 1e5 + 10;
#define lrt rt << 1
#define rrt rt << 1 | 1
#define lson l, mid, lrt
#define rson mid + 1, r, rrt
#define _rep(i,a,n) for (int i = (a); i <= (n); ++i)
struct node {
int l, r;
int sum, max, lazy;
int mid () { return (l + r) >> 1; }
void set (int l, int r, int lazy = 0) { this->l = l, this->r = r, this->lazy = lazy; }
node () { l = r = sum = max = lazy = 0; }
node (int l, int r, int s, int m, int la) : l(l), r(r), sum(s), max(m), lazy(la) {}
} ;
int n, k, c;
int a[maxn];
char str[7];
node T[maxn << 2];
inline void pushup (int rt) {
T[rt].sum = T[lrt].sum + T[rrt].sum;
T[rt].max = max(T[lrt].max, T[rrt].max);
}
inline void pushdown (int rt) {
if (T[rt].lazy == 0) return ;
T[lrt].lazy += T[rt].lazy;
T[lrt].sum += T[rt].lazy * (T[lrt].r - T[lrt].l + 1);
T[lrt].max += T[rt].lazy;
T[rrt].lazy += T[rt].lazy;
T[rrt].sum += T[rt].lazy * (T[rrt].r - T[rrt].l + 1);
T[rrt].max += T[rt].lazy;
T[rt].lazy = 0;
}
void build (int l, int r, int rt) {
T[rt].l = l, T[rt].r = r, T[rt].lazy = 0;
if (l == r) return(void)( T[rt].sum = T[rt].max = a[l] );
int mid = T[rt].mid();
build(lson);
build(rson);
pushup(rt);
}
void update (int c, int l, int r, int rt) {
if (T[rt].l >= l && T[rt].r <= r) return (void) (
T[rt].lazy += c,
T[rt].sum += c * (T[rt].r - T[rt].l + 1),
T[rt].max += c
);
pushdown(rt);
int mid = T[rt].mid();
if (l <= mid) update(c, l, r, lrt);
if (r > mid) update(c, l, r, rrt);
pushup(rt);
}
int querySum (int l, int r, int rt) {
if (T[rt].l >= l && T[rt].r <= r) return T[rt].sum;
pushdown(rt);
int mid = T[rt].mid();
int sum = 0;
if (l <= mid) sum += querySum(l, r, lrt);
if (r > mid) sum += querySum(l, r, rrt);
return sum;
}
int queryMax (int l, int r, int rt) {
if (T[rt].l >= l && T[rt].r <= r) return T[rt].max;
pushdown(rt);
int mid = T[rt].mid();
int maxx = -inf;
if (l <= mid) maxx = max(maxx, queryMax(l, r, lrt));
if (r > mid) maxx = max(maxx, queryMax(l, r, rrt));
return maxx;
}
int cas;
void run () {
scanf("%d", &n);
_rep (i, 1, n) scanf("%d", a + i);
build(1, n, 1);
printf("Case %d:\n", ++cas);
while (~scanf("%s", str)) {
if (str[0] == 'E') break;
scanf("%d%d", &k, &c);
if (str[0] == 'A') update(c, k, k, 1);
if (str[0] == 'S') update(-c, k, k, 1);
if (str[0] == 'Q') printf("%d\n", querySum(k, c, 1));
}
}
int main () {
int _T;
scanf("%d", &_T);
while (_T--) run();
}
2. I Hate It HDU - 1754
难度: ★【入门题】
题意: 中文题面不加赘述
题解: 检验模板题,用到单点修改和区间查询。
刚开始整理,比较粗糙的模板,不一定全面还比较冗长,见谅
#include<bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 2e5 + 10;
#define lrt rt << 1
#define rrt rt << 1 | 1
#define lson l, mid, lrt
#define rson mid + 1, r, rrt
#define _rep(i,a,n) for (int i = (a); i <= (n); ++i)
struct node {
int l, r;
int sum, max, lazy;
int mid () { return (l + r) >> 1; }
void set (int l, int r, int lazy = 0) { this->l = l, this->r = r, this->lazy = lazy; }
node () { l = r = sum = max = lazy = 0; }
node (int l, int r, int s, int m, int la) : l(l), r(r), sum(s), max(m), lazy(la) {}
} ;
int n, m, k, c;
int a[maxn];
char str[7];
node T[maxn << 2];
inline void pushup (int rt) {
T[rt].sum = T[lrt].sum + T[rrt].sum;
T[rt].max = max(T[lrt].max, T[rrt].max);
}
inline void pushdown (int rt) {
if (T[rt].lazy == 0) return ;
T[lrt].lazy += T[rt].lazy;
T[lrt].sum += T[rt].lazy * (T[lrt].r - T[lrt].l + 1);
T[lrt].max += T[rt].lazy;
T[rrt].lazy += T[rt].lazy;
T[rrt].sum += T[rt].lazy * (T[rrt].r - T[rrt].l + 1);
T[rrt].max += T[rt].lazy;
T[rt].lazy = 0;
}
void build (int l, int r, int rt) {
T[rt].l = l, T[rt].r = r, T[rt].lazy = 0;
if (l == r) return(void)( T[rt].sum = T[rt].max = a[l] );
int mid = T[rt].mid();
build(lson);
build(rson);
pushup(rt);
}
void change (int c, int k, int rt) {
if (T[rt].l == T[rt].r && T[rt].l == k) return (void) (
T[rt].sum = c,
T[rt].max = c
);
int mid = T[rt].mid();
if (k <= mid) change(c, k, lrt);
else change(c, k, rrt);
pushup(rt);
}
void update (int c, int l, int r, int rt) {
if (T[rt].l >= l && T[rt].r <= r) return (void) (
T[rt].lazy += c,
T[rt].sum += c * (T[rt].r - T[rt].l + 1),
T[rt].max += c
);
pushdown(rt);
int mid = T[rt].mid();
if (l <= mid) update(c, l, r, lrt);
if (r > mid) update(c, l, r, rrt);
pushup(rt);
}
int querySum (int l, int r, int rt) {
if (T[rt].l >= l && T[rt].r <= r) return T[rt].sum;
pushdown(rt);
int mid = T[rt].mid();
int sum = 0;
if (l <= mid) sum += querySum(l, r, lrt);
if (r > mid) sum += querySum(l, r, rrt);
return sum;
}
int queryMax (int l, int r, int rt) {
if (T[rt].l >= l && T[rt].r <= r) return T[rt].max;
pushdown(rt);
int mid = T[rt].mid();
int maxx = -inf;
if (l <= mid) maxx = max(maxx, queryMax(l, r, lrt));
if (r > mid) maxx = max(maxx, queryMax(l, r, rrt));
return maxx;
}
void run () {
scanf("%s%d%d", str, &k, &c);
if (str[0] == 'U') return (void)(change(c, k, 1));
printf("%d\n", queryMax(k, c, 1));
}
int main () {
while (~scanf("%d%d", &n, &m)) {
_rep (i, 1, n) scanf("%d", a + i);
build(1, n, 1);
while (m--) run();
}
}
3. A Simple Problem with Integers POJ - 3468
难度: ★【入门题】
题意: 区间修改和区间查询
题解: 考察线段树的区间修改和区间查询
#include<iostream>
using namespace std;
const int maxn = 1e5 + 10;
#define lrt rt << 1
#define rrt rt << 1 | 1
#define lson l, mid, lrt
#define rson mid + 1, r, rrt
#define ll long long
#define _rep(i,a,n) for (int i = (a); i <= (n); ++i)
struct node {
int l, r;
ll lazy, sum;
int mid () { return (l + r) >> 1; }
node () { l = r = lazy = sum = 0; }
};
int n, m;
ll a[maxn];
node T[maxn << 2];
inline void pushup (int rt) { T[rt].sum = T[lrt].sum + T[rrt].sum; }
inline void pushdown (int rt) {
if (T[rt].lazy == 0) return ;
T[lrt].lazy += T[rt].lazy;
T[rrt].lazy += T[rt].lazy;
T[lrt].sum += T[rt].lazy * (T[lrt].r - T[lrt].l + 1);
T[rrt].sum += T[rt].lazy * (T[rrt].r - T[rrt].l + 1);
T[rt].lazy = 0;
}
void build (int l, int r, int rt) {
T[rt].l = l, T[rt].r = r, T[rt].lazy = 0;
if (l == r) return (void)(T[rt].sum = a[l]);
int mid = T[rt].mid();
build(lson);
build(rson);
pushup(rt);
}
void update (ll c, int l, int r, int rt) {
if (T[rt].l >= l && T[rt].r <= r) return (void) (
T[rt].lazy += c,
T[rt].sum += c * (T[rt].r - T[rt].l + 1)
);
pushdown(rt);
int mid = T[rt].mid();
if (l <= mid) update(c, l, r, lrt);
if (r > mid) update(c, l, r, rrt);
pushup(rt);
}
ll query (int l, int r, int rt) {
if (T[rt].l >= l && T[rt].r <= r) return T[rt].sum;
pushdown(rt);
int mid = T[rt].mid();
ll res = 0;
if (l <= mid) res += query(l, r, lrt);
if (r > mid) res += query(l, r, rrt);
return res;
}
void run () {
_rep (i, 1, n) scanf("%lld", a + i);
build(1, n, 1);
while (m--) {
int l, r, c;
char str[2];
scanf("%s%d%d", str, &l, &r);
if (str[0] == 'Q') printf("%lld\n", query(l, r, 1));
else {
scanf("%d", &c);
update((ll)c, l, r, 1);
}
}
}
int main () {
while (~scanf("%d%d", &n, &m)) run();
}
4. Mayor’s posters POJ - 2528
难度: ★★
题意: 在一块广告牌上贴很多的广告【相同位置会覆盖上去】,问最后一共能看到多少广告
题解: 每个位置不同广告则进行不同的染色。问题在于这个题目的区间非常大,需要进行离散化。光是一般的离散化还不够,比如离散化之后,{1, 6}、{1,3}和{4,6}分别有三块广告牌,肉眼分析后两张广告会完全覆盖掉第一张广告的,但是这样的数据去查询区间[3,4]会告诉你是第一张广告牌。因此离散化的时候还要特别处理这个问题。
- 处理办法是如果{1,3}上有心的广告,则对线段树的区间{1,4}进行更新,就是要覆盖多一个单位。
- 那么进行离散化的时候,就要多预留这样的一个单位
#include<iostream>
#include<algorithm>
#include<set>
using namespace std;
#define _for(i,a,n) for (int i = (a); i < (n); ++i)
#define _rep(i,a,n) for (int i = (a); i <= (n); ++i)
#define lrt rt << 1
#define rrt rt << 1 | 1
#define lson l, mid, lrt
#define rson mid + 1, r, rrt
const int maxn = 1e5 + 10;
struct node {
int l, r, col;
int mid () { return l + r >> 1; }
node () { l = r = col = 0; }
};
int _T, n, cnt;
int len[maxn];
int l[maxn];
int r[maxn];
node T[maxn << 2];
void build (int l, int r, int rt) {
T[rt].l = l, T[rt].r = r;
if (l == r) return ;
int mid = T[rt].mid();
build(lson);
build(rson);
}
void pushdown (int rt) {
if (T[rt].col == 0) return ;
T[lrt].col = T[rt].col;
T[rrt].col = T[rt].col;
T[rt].col = 0;
}
void update (int col, int l, int r, int rt) {
if (T[rt].l >= l && T[rt].r <= r) return (void)( T[rt].col = col );
pushdown(rt);
int mid = T[rt].mid();
if (l <= mid) update(col, l, r, lrt);
if (r > mid) update(col, l, r, rrt);
}
int query (int k, int rt) {
if (T[rt].l == T[rt].r && T[rt].l == k) return T[rt].col;
pushdown(rt);
int mid = T[rt].mid();
if (k <= mid) return query(k, lrt);
return query(k, rrt);
}
void run () {
cnt = 0;
scanf("%d", &n);
_rep (i, 1, n) {
scanf("%d%d", l + i, r + i);
len[++cnt] = l[i];
len[++cnt] = r[i];
}
sort(len + 1, len + cnt + 1);
int tem = cnt = unique(len + 1, len + cnt + 1) - len - 1;
_rep (i, 2, tem) if (len[i] - len[i - 1] > 1) len[++cnt] = len[i] - 1;
sort(len + 1, len + cnt + 1);
build(1, cnt, 1);
_rep (i, 1, n) {
int powl = lower_bound(len + 1, len + cnt + 1, l[i]) - len;
int powr = lower_bound(len + 1, len + cnt + 1, r[i]) - len;
update(i, powl, powr, 1);
}
set<int> st;
_rep (i, 1, cnt) {
int col = query(i, 1);
if (col) st.insert(col);
}
printf("%d\n", st.size());
}
int main () {
scanf("%d", &_T);
while (_T--) run();
return 0;
}
5. Just a Hook HDU - 1698
难度: ★【入门题】
题意: 一个长度为 n n n的钩子,其中每一段的权值为1,每次将某个区间的所有值修改为 k k k,最后问整个钩子的权值和。
题解: 区间修改的模板题【有些区间修改是增量的,这个是直接改变成某值】
#include<bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 2e5 + 10;
#define lrt rt << 1
#define rrt rt << 1 | 1
#define lson l, mid, lrt
#define rson mid + 1, r, rrt
#define _rep(i,a,n) for (int i = (a); i <= (n); ++i)
struct node {
int l, r;
int sum, lazy;
int mid () { return (l + r) >> 1; }
node () { l = r = sum = lazy = 0; }
node (int l, int r, int s, int la) : l(l), r(r), sum(s), lazy(la) {}
} ;
int n, m;
int a[maxn];
char str[7];
node T[maxn << 2];
inline void pushup (int rt) {
T[rt].sum = T[lrt].sum + T[rrt].sum;
}
inline void pushdown (int rt) {
if (T[rt].lazy == 0) return ;
T[lrt].lazy = T[rt].lazy;
T[lrt].sum = T[rt].lazy * (T[lrt].r - T[lrt].l + 1);
T[rrt].lazy = T[rt].lazy;
T[rrt].sum = T[rt].lazy * (T[rrt].r - T[rrt].l + 1);
T[rt].lazy = 0;
}
void build (int l, int r, int rt) {
T[rt].l = l, T[rt].r = r, T[rt].lazy = 0;
if (l == r) return(void)( T[rt].sum = a[l] );
int mid = T[rt].mid();
build(lson);
build(rson);
pushup(rt);
}
void change (int c, int l, int r, int rt) {
if (T[rt].l >= l && T[rt].r <= r) return (void)(
T[rt].lazy = c,
T[rt].sum = c * (T[rt].r - T[rt].l + 1)
);
pushdown(rt);
int mid = T[rt].mid();
if (l <= mid) change(c, l, r, lrt);
if (r > mid) change(c, l, r, rrt);
pushup(rt);
}
void run (int cas) {
scanf("%d", &n);
_rep (i, 1, n) a[i] = 1;
build(1, n, 1);
scanf("%d", &m);
while (m--) {
int l, r, c;
scanf("%d%d%d", &l, &r, &c);
change(c, l, r, 1);
}
printf("Case %d: The total value of the hook is %d.\n", cas, T[1].sum);
}
int main () {
int _T;
scanf("%d", &_T);
_rep (i, 1, _T) run(i);
}
7. Balanced Lineup POJ - 3264
难度: ★
题意: 查询区间内的最大差值
题解: 只有区间查询,写两个函数,一个查询区间最大值,一个查询区间最小值,减一下既得最大差值
#include<iostream>
#include<algorithm>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 5e4 + 10;
#define lrt rt << 1
#define rrt rt << 1 | 1
#define lson l, mid, lrt
#define rson mid + 1, r, rrt
#define _rep(i,a,n) for (int i = (a); i <= (n); ++i)
struct node {
int l, r, min, max;
int mid () { return l + r >> 1; }
node () { l = r = max = 0, min = inf; }
};
int n, m, l, r;
int a[maxn];
node T[maxn << 2];
inline void pushup (int rt) {
T[rt].max = max(T[lrt].max, T[rrt].max);
T[rt].min = min(T[lrt].min, T[rrt].min);
}
void build (int l, int r, int rt) {
T[rt].l = l, T[rt].r = r;
if (l == r) return (void)(T[rt].max = T[rt].min = a[l]);
int mid = T[rt].mid();
build(lson);
build(rson);
pushup(rt);
}
int queryMax (int l, int r, int rt) {
if (T[rt].l >= l && T[rt].r <= r) return T[rt].max;
int mid = T[rt].mid();
int res = 0;
if (l <= mid) res = max(res, queryMax(l, r, lrt));
if (r > mid) res = max(res, queryMax(l, r, rrt));
return res;
}
int queryMin (int l, int r, int rt) {
if (T[rt].l >= l && T[rt].r <= r) return T[rt].min;
int mid = T[rt].mid();
int res = inf;
if (l <= mid) res = min(res, queryMin(l, r, lrt));
if (r > mid) res = min(res, queryMin(l, r, rrt));
return res;
}
void run () {
_rep (i, 1, n) scanf("%d", a + i);
build(1, n, 1);
while (m--) {
scanf("%d%d", &l, &r);
printf("%d\n", queryMax(l, r, 1) - queryMin(l, r, 1));
}
}
int main () {
while (~scanf("%d%d", &n, &m)) run();
}
8. Can you answer these queries? HDU - 4027
难度: ★
题意: [ 1 , n ] [1,n] [1,n]区间有一个好感度,每次操作会对一个区间内的所有好感度进行开平方根处理,查询则是对一个区间的求和。
题解: 考察线段树的区间修改和区间查询。区别在于区间修改部分,因为是对每一个好感度进行开平方根,所以原则上应该是落实到单点修改的。但是有一个细节在于比方说我某个区间的所有好感度早就开根到1了,接下来无论怎么开根都不会变化,主要针对这里进行优化。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
#define lrt rt << 1
#define rrt rt << 1 | 1
struct node {
int l, r;
ll sum;
int mid () { return l + r >> 1; }
node () { l = r = sum = 0; }
};
int n, m;
ll a[maxn];
node T[maxn << 2];
void pushup (int rt) { T[rt].sum = T[lrt].sum + T[rrt].sum; }
void build (int l, int r, int rt) {
T[rt].l = l, T[rt].r = r;
if (l == r) return (void)(T[rt].sum = a[l]);
int mid = T[rt].mid();
build(l, mid, lrt);
build(mid + 1, r, rrt);
pushup(rt);
}
void update (int l, int r, int rt) {
if (T[rt].sum == T[rt].r - T[rt].l + 1) return ;
if (T[rt].l == T[rt].r) return (void)(T[rt].sum = sqrt(T[rt].sum));
int mid = T[rt].mid();
if (l <= mid) update(l, r, lrt);
if (r > mid) update(l, r, rrt);
pushup(rt);
}
ll query (int l, int r, int rt) {
if (T[rt].l >= l && T[rt].r <= r) return T[rt].sum;
int mid = T[rt].mid();
ll res = 0;
if (l <= mid) res += query(l, r, lrt);
if (r > mid) res += query(l, r, rrt);
return res;
}
void run () {
for (int i = 1; i <= n; ++i) scanf("%lld", a + i);
build(1, n, 1);
scanf("%d", &m);
while (m--) {
int k, l, r;
scanf("%d%d%d", &k, &l, &r);
if (l > r) swap(l, r);
if (k == 0) update(l, r, 1);
else printf("%lld\n", query(l, r, 1));
}
}
int cas;
int main () {
while (~scanf("%d", &n)) {
printf("Case #%d:\n", ++cas);
run();
puts("");
}
return 0;
}
9. Tunnel Warfare HDU - 1540
难度: ★★
题意: 有 n n n个村庄排成一列,相邻的两个村庄表示相互连接。 D i Di Di表示摧毁第 i i i个村庄,并且切断了与其他村庄的联系; Q i Qi Qi表示询问能与第 i i i个村庄联系的村庄数; R R R表示恢复上一个被摧毁的村庄。
题解: 不同于求和和取最大值,这个关乎到了连续的区间。因此需要在线段树中记录两个值, L m a x Lmax Lmax表示这个区间前段连续的长度, R m a x Rmax Rmax表示这个区间后段连续的长度
#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e4 + 10;
#define lrt rt << 1
#define rrt rt << 1 | 1
struct node {
int l, r;
int Lmax, Rmax;
int mid () { return l + r >> 1; }
};
int n, m;
int a[maxn];
node T[maxn << 2];
stack<int> st;
void pushup (int rt) {
node L = T[lrt], R = T[rrt];
T[rt].Lmax = L.Lmax + (L.Lmax == L.r - L.l + 1 ? R.Lmax : 0);
T[rt].Rmax = R.Rmax + (R.Rmax == R.r - R.l + 1 ? L.Rmax : 0);
}
void build (int l, int r, int rt) {
T[rt].l = l, T[rt].r = r;
T[rt].Lmax = T[rt].Rmax = r - l + 1;
if (l == r) return ;
int mid = T[rt].mid();
build(l, mid, lrt);
build(mid + 1, r, rrt);
}
void update (int c, int k, int rt) {
if (T[rt].l == T[rt].r && T[rt].l == k) return (void)(
T[rt].Lmax = T[rt].Rmax = c
);
int mid = T[rt].mid();
if (k <= mid) update(c, k, lrt);
else update(c, k, rrt);
pushup(rt);
}
int query (int k, int rt) {
int mid = T[rt].mid();
if (k <= mid) {
if (k >= T[lrt].r - T[lrt].Rmax + 1) return T[lrt].Rmax + T[rrt].Lmax;
return query(k, lrt);
}
if (k <= T[rrt].l + T[rrt].Lmax - 1) return T[lrt].Rmax + T[rrt].Lmax;
return query(k, rrt);
}
void run () {
int k;
char s[10];
scanf("%s", s);
if (s[0] == 'R') {
if (st.empty()) return;
update(1, st.top(), 1);
st.pop();
} else {
scanf("%d", &k);
if (s[0] == 'Q') printf("%d\n", query(k, 1));
else {
st.push(k);
update(0, k, 1);
}
}
}
int main () {
while (~scanf("%d%d", &n, &m)) {
build(1, n, 1);
while (st.size()) st.pop();
while (m--) run();
}
return 0;
}
10. Assign the task HDU - 3974
难度: ★★
题意: 有一棵代表上下级关系的树,给某个节点发布的任务,会下发到这个节点下的所有节点。询问的是单个点当前的任务。
题解: 任务的发布和询问只是一个染色问题而已,只是常规的线段树。但是题目的输入需要一波处理,因为给的是一些节点的关系。因为题目保证是一棵有根树,找到根节点之后DFS对每个节点进行一个区间的规划,然后就是常规的线段树部分。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e4 + 10;
#define lrt rt << 1
#define rrt rt << 1 | 1
#define _for(i,a,n) for (int i = (a); i < (n); ++i)
#define _rep(i,a,n) for (int i = (a); i <= (n); ++i)
struct node {
int l, r, color;
int mid () { return l + r >> 1; }
node () { color = -1; }
};
int _T, n, m, cnt;
int vis[maxn];
int mapL[maxn];
int mapR[maxn];
node T[maxn << 3];
vector<int> G[maxn];
void dfs (int u) {
mapL[u] = ++cnt;
for (auto v : G[u]) dfs(v);
mapR[u] = ++cnt;
}
void build (int l, int r, int rt) {
T[rt].l = l, T[rt].r = r, T[rt].color = -1;
if (l == r) return ;
int mid = T[rt].mid();
build(l, mid, lrt);
build(mid + 1, r, rrt);
}
void pushdown (int rt) {
if (T[rt].color == -1) return;
T[lrt].color = T[rt].color;
T[rrt].color = T[rt].color;
T[rt].color = -1;
}
void update (int c, int l, int r, int rt) {
if (T[rt].l >= l && T[rt].r <= r) return (void)( T[rt].color = c );
pushdown(rt);
int mid = T[rt].mid();
if (l <= mid) update(c, l, r, lrt);
if (r > mid) update(c, l, r, rrt);
}
int query (int k, int rt) {
if (T[rt].l == T[rt].r && T[rt].l == k) return T[rt].color;
if (T[rt].color != -1) return T[rt].color;
int mid = T[rt].mid();
if (k <= mid) return query(k, lrt);
return query(k, rrt);
}
int cas;
void run () {
printf("Case #%d:\n", ++cas);
cnt = 0;
memset(vis, 0, sizeof vis);
memset(mapL, 0, sizeof mapL);
memset(mapR, 0, sizeof mapR);
_for (i, 0, maxn) G[i].clear();
scanf("%d", &n);
build(1, n << 1, 1);
_for (i, 1, n) {
int u, v;
scanf("%d%d", &u, &v);
G[v].push_back(u);
vis[u] = 1;
}
_rep (i, 1, n) if (!vis[i]) dfs(i);
scanf("%d", &m);
while (m--) {
char s[10];
int x, y;
scanf("%s%d", s, &x);
if (s[0] == 'C') printf("%d\n", query(mapL[x], 1));
else {
scanf("%d", &y);
update(y, mapL[x], mapR[x], 1);
}
}
}
int main () {
scanf("%d", &_T);
while (_T--) run();
return 0;
}
11. Transformation HDU - 4578
难度: ★★
题意: 很长的题面——狄仁杰断案,我和元芳一样懵。本质上就是三种区间操作和一个区间查询,一种是区间内所有数 + c +c +c,一种是区间内所有数 ∗ c *c ∗c,最后一种是区间内所有数 = c =c =c。查询也有一些特殊,求的是所有数的k次幂的和。
题解: 线段树中记录两个内容: v a l val val记录值, f l a g = 1 flag = 1 flag=1表示这个区间内所有节点的值相同。向下查询的时候,到某个区间发现 f l a g = 1 flag = 1 flag=1则不需要再向下查询,调用val即可。区间更新的时候,也要特别地对flag进行更新。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 7;
const int mod = 10007;
#define lrt rt << 1
#define rrt rt << 1 | 1
struct node {
int l, r;
int flag, val;
int mid () { return l + r >> 1; }
node () { flag = 1, val = 0; }
};
int n, m;
node T[maxn << 2];
void pushup (int rt) {
if (!T[lrt].flag || !T[rrt].flag) return (void)(T[rt].flag = 0);
if (T[lrt].val != T[rrt].val) return (void)(T[rt].flag = 0);
T[rt].flag = 1, T[rt].val = T[lrt].val;
}
void pushdown (int rt) {
if (T[rt].flag == 0) return ;
T[lrt].val = T[rrt].val = T[rt].val;
T[rt].flag = 0;
}
void build (int l, int r, int rt) {
T[rt].l = l, T[rt].r = r, T[rt].flag = 1, T[rt].val = 0;
if (l == r) return ;
int mid = T[rt].mid();
build(l, mid, lrt);
build(mid + 1, r, rrt);
}
void update (int op, int c, int l, int r, int rt) {
if (T[rt].l >= l && T[rt].r <= r && T[rt].flag) {
if (op == 1) T[rt].val += c;
if (op == 2) T[rt].val = (T[rt].val * c) % mod;
if (op == 3) T[rt].val = c;
return ;
}
pushdown(rt);
int mid = T[rt].mid();
if (l <= mid) update(op, c, l, r, lrt);
if (r > mid) update(op, c, l, r, rrt);
pushup(rt);
}
int query (int k, int l, int r, int rt) {
if (T[rt].l >= l && T[rt].r <= r && T[rt].flag) {
int ans = 1;
while (k--) ans = (ans * T[rt].val) % mod;
ans = (ans * (T[rt].r - T[rt].l + 1)) % mod;
return ans;
}
pushdown(rt);
int mid = T[rt].mid();
int ans = 0;
if (l <= mid) ans += query(k, l, r, lrt);
if (r > mid) ans += query(k, l, r, rrt);
return ans % mod;
}
void run () {
build(1, n, 1);
while (m--) {
int op, x, y, c;
scanf("%d%d%d%d", &op, &x, &y, &c);
if (op == 4) printf("%d\n", query(c, x, y, 1));
else update(op, c, x, y, 1);
}
}
int main () {
while (~scanf("%d%d", &n, &m) && (n + m)) run();
return 0;
}
12. Vases and Flowers HDU - 4614
难度: ★★
题意: 有 n n n个花瓶,初始时都为空,每个花瓶最多放一朵花。一种操作为从第 i i i个花瓶开始,一共放入 k k k多花,并输出插入花的第一个花瓶和最后一个花瓶;另一种操作将某个区间内的所有花全部取出,并输出花的数量。
题解: 对于插入时第一个花瓶和最后一个花瓶,则用二分去查找。线段树则用来记录每个区间的花的数量。
关于二分的细节:
search(int res, int l, int r, int rt)
函数用来查询区间 [ l , r ] [l,r] [l,r]插入 r e s res res朵花的最后一个花瓶的位置。- 如果左半区间能够插入 r e s res res朵花,则带 r e s res res朵花向左半区间转移
- 如果左半区间只能插入 t e m tem tem朵花,则带 r e s − t e m res - tem res−tem朵花向右半区间转移
- 直到叶子节点,则是最后一个花瓶的位置
#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e4 + 7;
#define lrt rt << 1
#define rrt rt << 1 | 1
struct node {
int l, r, sum;
int mid () { return l + r >> 1; }
};
int _T, n, m;
int ansL, ansR;
node T[maxn << 2];
void build (int l, int r, int rt) {
T[rt].l = l, T[rt].r = r, T[rt].sum = 0;
if (l == r) return ;
int mid = T[rt].mid();
build(l, mid, lrt);
build(mid + 1, r, rrt);
}
void pushup (int rt) { T[rt].sum = T[lrt].sum + T[rrt].sum; }
void pushdown (int rt) {
if (T[rt].sum == T[rt].r - T[rt].l + 1) {
T[lrt].sum = T[lrt].r - T[lrt].l + 1;
T[rrt].sum = T[rt].sum - T[lrt].sum;
}
if (T[rt].sum == 0) T[lrt].sum = T[rrt].sum = 0;
}
void update (int c, int l, int r, int rt) {
if (T[rt].l >= l && T[rt].r <= r) return (void)(
T[rt].sum = (T[rt].r - T[rt].l + 1) * c
);
pushdown(rt);
int mid = T[rt].mid();
if (l <= mid) update(c, l, r, lrt);
if (r > mid) update(c, l, r, rrt);
pushup(rt);
}
int query (int l, int r, int rt) {
if (T[rt].l >= l && T[rt].r <= r) return T[rt].sum;
pushdown(rt);
int mid = T[rt].mid();
int res = 0;
if (l <= mid) res += query(l, r, lrt);
if (r > mid) res += query(l, r, rrt);
return res;
}
int search (int res, int l, int r, int rt) {
if (l == r) return l;
pushdown(rt);
int mid = T[rt].mid();
int resL = (T[lrt].r - T[lrt].l + 1) - T[lrt].sum;
if (res <= resL) return search(res, l, mid, lrt);
return search(res - resL, mid + 1, r, rrt);
}
void run () {
scanf("%d%d", &n, &m);
build(1, n, 1);
while (m--) {
int k, x, y;
scanf("%d%d%d", &k, &x, &y);
if (k == 1) {
x++;
int tem = n - x + 1 - query(x, n, 1);
if (tem == 0) printf("Can not put any one.\n");
else {
y = min(y, tem);
int num = (x > 1 ? x - 1 - query(1, x - 1, 1) : 0);
int bg = search(num + 1, 1, n, 1);
int ed = search(num + y, 1, n, 1);
printf("%d %d\n", bg - 1, ed - 1);
update(1, bg, ed, 1);
}
} else {
x++, y++;
printf("%d\n", query(x, y, 1));
update(0, x, y, 1);
}
}
puts("");
}
int main () {
scanf("%d", &_T);
while (_T--) run();
return 0;
}