Codeforces Round #218 (Div. 2) (线段树区间处理)
2013-12-08 21:26
453 查看
A,B大水题,不过B题逗比了题意没理解清楚,讲的太不清楚了感觉= =还是英语弱,白白错了两发。
C:
二分答案判断是否可行,也逗比了下。。。二分的上界开太大导致爆long long了。。。
D:
看完题想都不想就用线段树搞起了,虽然我知道并查集很简单。。不过没用并查集写过区间处理的问题就不用多想了。。
刚开始时,所有的船都是空的,也就是说可放的水量是船的容量,然后对于第一个操作,意思就是从第x个数开始减小直到减小了p或者后面都变成0了。这里我就二分查找下最右边的会减小的数R,然后把x~R-1的数都清零,对于第R个数计算出剩余量后单点更新,mark[rt] = true表示这段区间被清零了,第二个操作直接单点询问。
E:
给你n个地铁站的位置,都是在x轴上的点,选出k个点使得k个点两两之间的距离和最小。
思路:
首先肯定是对n个点排序,这样子之后k个点肯定是排完序之后某段连续的k个。
所以可以枚举起始位置计算该位置开始的k个距离和,现在的问题就是如何O(1)的计算出该位置的结果。
假设我知道了 区间(L, R)的两两距离和,考虑区间 (L , R) 如何O(1)推出区间(L+1, R+1),转移其实就是去掉L点,加上R+1点,很容易知道原来的距离和减小了L到其他点的距离s1,增加了R+1到其他点的距离s2,画个图很容易得到s1+s2 = (L到R+1的距离)*(k-1),也就是说我只需要知道了L到其他点的距离和,就可以推出转移之后的两两距离和的值,所以说只需要维护上一次的两两距离和and 前一个区间的L到其他点的距离和即可。具体见代码~
这个E题实在是伤,比赛最后十分钟敲完交上了WA,最后竟然是给定的每个位置不是递增的,输出的时候要输出id,前面居然没把这个写上来= =伤,还是太弱
C:
二分答案判断是否可行,也逗比了下。。。二分的上界开太大导致爆long long了。。。
#include #include #include using namespace std; typedef __int64 ll; char s[111]; int B, S, C, pb, ps, pc; ll r, cnt[222]; int ok(ll m) { ll tot = r; ll BB = cnt['B'-'A']*m, SS = cnt['S'-'A']*m, CC = cnt['C'-'A']*m; if(BB > B) { BB -= B; tot -= BB*pb; } if(SS > S) { SS -= S; tot -= SS*ps; } if(CC > C) { CC -= C; tot -= CC*pc; } return tot >= 0; } int main() { scanf("%s", s); int len = strlen(s); for(int i = 0;i < len; i++) cnt[s[i]-'A']++; scanf("%d%d%d", &B, &S, &C); scanf("%d%d%d", &pb, &ps, &pc); scanf("%I64d", &r); ll L = 0, R = 100000000000000LL; ll ans = 0; while(L <= R) { ll mid = (L + R)/2; if(ok(mid)) { ans = mid; L = mid+1; } else R = mid-1; } printf("%I64d\n", ans); return 0; }
D:
看完题想都不想就用线段树搞起了,虽然我知道并查集很简单。。不过没用并查集写过区间处理的问题就不用多想了。。
刚开始时,所有的船都是空的,也就是说可放的水量是船的容量,然后对于第一个操作,意思就是从第x个数开始减小直到减小了p或者后面都变成0了。这里我就二分查找下最右边的会减小的数R,然后把x~R-1的数都清零,对于第R个数计算出剩余量后单点更新,mark[rt] = true表示这段区间被清零了,第二个操作直接单点询问。
#include #include #include using namespace std; #define lson rt<<1, l, mid #define rson rt<<1|1, mid+1, r typedef __int64 ll; const int maxn = 200000 + 10; ll sum[maxn<<2], a[maxn]; bool mark[maxn<<2]; int n; void up(int rt) { sum[rt] = sum[rt<<1] + sum[rt<<1|1]; } void create(int rt, int l, int r) { mark[rt] = false; if(l == r) { sum[rt] = a[l]; return ; } int mid = (l + r)/2; create(lson); create(rson); up(rt); } void down(int rt) { if(mark[rt]) { mark[rt<<1] = mark[rt<<1|1] = true; sum[rt<<1] = sum[rt<<1|1] = 0; } } void update1(int rt, int l, int r, int L, int R) { if(L > R) return; if(L <= l && R >= r) { mark[rt] = true; sum[rt] = 0; return ; } down(rt); int mid = (l + r)/2; if(L <= mid) update1(lson, L, R); if(R > mid) update1(rson, L, R); up(rt); } void update2(int rt, int l, int r, int x, ll val) { if(l == r) { sum[rt] = val; return ; } down(rt); int mid = (l + r)/2; if(x <= mid) update2(lson, x, val); else update2(rson, x, val); up(rt); } ll query(int rt, int l, int r, int L, int R) { if(L <= l && R >= r) { return sum[rt]; } down(rt); int mid = (l + r)/2; ll ret = 0; if(L <= mid) ret += query(lson, L, R); if(R > mid) ret += query(rson, L, R); up(rt); return ret; } int main() { scanf("%d", &n); for(int i = 1;i <= n; i++) scanf("%I64d", &a[i]); create(1, 1, n); int m, op, x, p; scanf("%d", &m); while(m--) { scanf("%d", &op); if(op == 1) { scanf("%d%d", &x, &p); int L = x, R = n, pos = n; ll tot = -1; while(L <= R) { int mid = (L + R)/2; ll cur = query(1, 1, n, x, mid); if(cur >= p) { tot = cur; pos = mid; R = mid-1; } else L = mid+1; } // printf("x = %d p = %d tot = %I64d pos = %d\n", x, p, tot, pos); if(tot == -1) { update1(1, 1, n, x, n); } else { update1(1, 1, n, x, pos-1); // printf("!!!!!! %d\n", tot - p); update2(1, 1, n, pos, tot - p); } } else { scanf("%d", &x); printf("%I64d\n", a[x] - query(1, 1, n, x, x)); } // printf("%I64d %I64d\n", query(1, 1, n, 1, 1), query(1, 1, n, 2, 2)); } return 0; }
E:
给你n个地铁站的位置,都是在x轴上的点,选出k个点使得k个点两两之间的距离和最小。
思路:
首先肯定是对n个点排序,这样子之后k个点肯定是排完序之后某段连续的k个。
所以可以枚举起始位置计算该位置开始的k个距离和,现在的问题就是如何O(1)的计算出该位置的结果。
假设我知道了 区间(L, R)的两两距离和,考虑区间 (L , R) 如何O(1)推出区间(L+1, R+1),转移其实就是去掉L点,加上R+1点,很容易知道原来的距离和减小了L到其他点的距离s1,增加了R+1到其他点的距离s2,画个图很容易得到s1+s2 = (L到R+1的距离)*(k-1),也就是说我只需要知道了L到其他点的距离和,就可以推出转移之后的两两距离和的值,所以说只需要维护上一次的两两距离和and 前一个区间的L到其他点的距离和即可。具体见代码~
这个E题实在是伤,比赛最后十分钟敲完交上了WA,最后竟然是给定的每个位置不是递增的,输出的时候要输出id,前面居然没把这个写上来= =伤,还是太弱
#include #include #include using namespace std; typedef __int64 ll; const int maxn = 300000 + 10; ll a[maxn], sum[maxn]; struct PP { int x, id; PP() {} PP(int x, int id): x(x), id(id) {} bool operator < (const PP &a) const { return x < a.x; } }st[maxn]; int main() { int n, k; scanf("%d", &n); for(int i = 1;i <= n; i++) scanf("%d", &st[i].x), st[i].id = i; sort(st + 1, st + n + 1); a[1] = 0; for(int i = 2;i <= n; i++) a[i] = a[i-1] + st[i].x - st[i-1].x; for(int i = 1;i <= n; i++) sum[i] = sum[i-1] + a[i]; scanf("%d", &k); ll cur = 0, des = 0; for(int i = 2;i <= k; i++) { des += a[i]*(k-i); cur += sum[k] - des; } ll mx = cur; int ans = 1; ll pre = sum[k]; // cur当前区间两两距离和,pre为当前区间L到其他点的距离和 for(int i = 2;i+k-1 <= n; i++) { cur = (a[i+k-1] - a[i-1])*(k-1) - pre*2 + cur; if(cur < mx) { ans = i; mx = cur; } pre = pre - (a[i] - a[i-1])*(k-1) + a[i+k-1] - a[i]; } while(k--) { printf("%d ", st[ans++].id); } puts(""); return 0; }
相关文章推荐
- Codeforces Round #149 (Div. 2) E. XOR on Segment(21棵线段树处理每一位+区间异或)
- Codeforces Round #222 (Div. 1) D. Developing Game 线段树有效区间合并
- Educational Codeforces Round 37 (Rated for Div. 2) F. SUM and REPLACE(线段树,区间更新)
- 【Codeforces Round 370 (Div 2) E】【线段树 等比数列 区间合并】Memory and Casinos 赌场区间[l,r] l进r先出的概率
- 【Codeforces Round 333 (Div 2)D】【线段树 or ST-RMQ 初始化78msAC】Lipshitz Sequence 若干区间询问所有子区间的答案和
- 线段树(待续)(区间每个数加上不同的斐波那契额数)Codeforces Round #FF (Div. 2)E
- Codeforces Round #400 (Div. 1 + Div. 2, combined) C - Molly's Chemicals 区间和问题
- 【Codeforces Round 263 (Div 2)E】【坐标映射 脑洞】Appleman and a Sheet of Paper 折纸游戏 区间查询
- 【Codeforces Round 334 (Div 2)C】【脑洞】Alternative Thinking 最多反转一个区间使得最长跳跃子串的长度尽可能长
- Codeforces Round #149 (Div. 2) E. XOR on Segment (线段树成段更新+二进制)
- Codeforces Round #218 (Div. 2)这场相对比较水啊
- cf/Codeforces Round #373 div1-C/div2-E Sasha and Array 线段树 + 维护矩阵快速幂
- Codeforces Round #400 (Div. 1 + Div. 2, combined) C - Molly's Chemicals 区间和问题
- Codeforces Round #200 (Div. 1) (树上的线段树)
- Codeforces Round #197 (Div. 2) D. Xenia and Bit Operations - 线段树
- Codeforces Round #FF (Div. 2)E(线段树成段更新)
- Codeforces Round #400 (Div. 1 + Div. 2, combined) C - Molly's Chemicals 区间和问题
- Codeforces Round #102 (Div. 2)总结(如何处理A*B*C==n!!!)
- Codeforces Round #174 (Div. 2) Cows and Sequence(线段树)
- CodeForces Round 213 Div 2 E Sereja and Brackets 线段树