SMOJ 2201 D (线段树)
来源:互联网 发布:淘宝购物积分怎么用 编辑:程序博客网 时间:2024/05/29 15:07
题目描述
这是一道数据结构题。
我们拥有一个长度为n的数组a[i]。
我们有m次操作。操作有两种类型:
0 i val:表示我们要把a[i]修改为val;
1 l r k:表示我们要求出区间[l,r]的最多k个不相交子区间,并使得各个子区间的数的和尽量大,需要注意的是,我们也可以不选择区间,这时候数的和为0.
N,m不超过10^5.
所有的ai和val的绝对值均不超过500.k不超过20.询问的数目不超过10000.
所有输入保证合法。
输入格式
第一行为数据组数。
对于每一组数据:
第一行为正整数n。
第二行n个整数表示ai。
第三行一个正整数m。
接下来m行每行一个操作。具体看题面。
输出格式
对于每一组数据:
对于每一组询问,一行一个整数表示答案。
输入样例
1
9
9 -8 9 -1 -1 -1 9 -8 9
3
1 1 9 1
1 1 9 2
1 4 6 3
输出样例
17
25
0
Solution
线段树好题 + 码农级数据结构题!
比赛时想着如何将dp改成数据结构(明显是线段树),结果没想出来。后来才知道具体做法很简单。每次在区间中找一段最大的,并将这个区间取反,就是变成它的相反数。然后每个询问直接做k次就行了。
至于为什么想一下就知道了。假如这次贪心地取影响了后面的,那么后面取到它的相反数,就去除了影响。这样就保证贪心没有“后效性”了。这点我觉得有点像网络流里的反向边。很神奇哦。
虽说想法是naive的,但写法是要命的。这题我写了一个晚上写完了,第二天调了半个下午无果,丢下去打球,打完球回到机房后灵光一现,改了一下函数实现方式就立马过了!(得出结论:我太菜鸡了QAQ。。)
这题的基础模型是动态修改+求区间连续最大和。这是很经典的线段树模型,维护的东西有Lmax, Rmax, Tmax,sum等,比较多。这题由于要取反,还要记最大区间的左右端点,同样还要借助于左连续一段和右连续一段。于是还要记Lmaxp, Rmaxp, Tmaxp1, Tmaxp2,还有翻转标记rev。对于取反,我是开了两棵线段树,取反就Swap。总之要维护的东西很多,查询要用到的也不少,代码将近200行左右。比起LCT什么的,不算太长。但一直码不对,就有可能心态爆炸。
需要注意的是,每次询问后记得取反回来之类的细节。
Code
#include <cstdio>#include <cstdlib>#include <iostream>#include <cmath>#include <cstring>#include <algorithm>#define MAXN 100010#define Max(a, b) ((a) > (b)) ? (a) : (b)#define INF 1e9using namespace std;int nG;int n, m;int a[MAXN];struct Tnode{ int Lmax, Rmax, Tmax; int sum, Lmaxp, Rmaxp, Tmaxp1, Tmaxp2; bool rev; Tnode() {} Tnode(int _a, int _b, int _c, int _d, int _e, int _f, int _g, int _h, bool _i){ Lmax = _a; Rmax = _b; Tmax = _c; sum = _d; Lmaxp = _e; Rmaxp = _f; Tmaxp1 = _g; Tmaxp2 = _h; rev = _i; }}tree[2][MAXN<<2];void Swap(Tnode& A, Tnode& B){ Tnode C = A; A = B; B = C;}void Up(Tnode& root, Tnode& Lson, Tnode& Rson){ root.sum = Lson.sum + Rson.sum; if(Lson.Lmax > Lson.sum + Rson.Lmax){ root.Lmax = Lson.Lmax; root.Lmaxp = Lson.Lmaxp; } else{ root.Lmax = Lson.sum + Rson.Lmax; root.Lmaxp = Rson.Lmaxp; } if(Rson.Rmax > Rson.sum + Lson.Rmax){ root.Rmax = Rson.Rmax; root.Rmaxp = Rson.Rmaxp; } else{ root.Rmax = Rson.sum + Lson.Rmax; root.Rmaxp = Lson.Rmaxp; } if(Lson.Tmax >= Rson.Tmax && Lson.Tmax >= Lson.Rmax + Rson.Lmax){ root.Tmax = Lson.Tmax; root.Tmaxp1 = Lson.Tmaxp1; root.Tmaxp2 = Lson.Tmaxp2; } else if(Rson.Tmax >= Lson.Tmax && Rson.Tmax >= Lson.Rmax + Rson.Lmax){ root.Tmax = Rson.Tmax; root.Tmaxp1 = Rson.Tmaxp1; root.Tmaxp2 = Rson.Tmaxp2; } else{ root.Tmax = Lson.Rmax + Rson.Lmax; root.Tmaxp1 = Lson.Rmaxp; root.Tmaxp2 = Rson.Lmaxp; } root.rev = false;}void Down(int root, int Lson, int Rson){ if(!tree[0][root].rev) return; Swap(tree[0][Lson], tree[1][Lson]); tree[0][Lson].rev ^= 1; tree[1][Lson].rev ^= 1; Swap(tree[0][Rson], tree[1][Rson]); tree[0][Rson].rev ^= 1; tree[1][Rson].rev ^= 1;}void build(int root, int L, int R){ if(L == R){ for(int i = 0; i < 2; i++){ if(!i) tree[i][root].Tmax = tree[i][root].Rmax = tree[i][root].Lmax = tree[i][root].sum = a[L]; else tree[i][root].Tmax = tree[i][root].Rmax = tree[i][root].Lmax = tree[i][root].sum = -a[L]; tree[i][root].Tmaxp1 = tree[i][root].Tmaxp2 = tree[i][root].Lmaxp = tree[i][root].Rmaxp = L; tree[i][root].rev = false; } return; } int mid = (L + R) >> 1, Lson = root << 1, Rson = root << 1 | 1; build(Lson, L, mid); build(Rson, mid+1, R); Up(tree[0][root], tree[0][Lson], tree[0][Rson]); Up(tree[1][root], tree[1][Lson], tree[1][Rson]);}void update(int root, int L, int R, int x, int v){ if(x > R || x < L) return; if(L == x && x == R){ tree[0][root].sum = v; tree[1][root].sum = -v; tree[0][root].Tmax = tree[0][root].Rmax = tree[0][root].Lmax = v; tree[1][root].Tmax = tree[1][root].Rmax = tree[1][root].Lmax = -v; return; } int mid = (L + R) >> 1, Lson = root << 1, Rson = root << 1 | 1; Down(root, Lson, Rson); update(Lson, L, mid, x, v); update(Rson, mid+1, R, x, v); Up(tree[0][root], tree[0][Lson], tree[0][Rson]); Up(tree[1][root], tree[1][Lson], tree[1][Rson]);}void flip(int root, int L, int R, int x, int y){ if(x > R || y < L) return; if(x <= L && y >= R){ Swap(tree[0][root], tree[1][root]); tree[0][root].rev ^= 1; tree[1][root].rev ^= 1; return; } int mid = (L + R) >> 1, Lson = root << 1, Rson = root << 1 | 1; Down(root, Lson, Rson); flip(Lson, L, mid, x, y); flip(Rson, mid+1, R, x, y); Up(tree[0][root], tree[0][Lson], tree[0][Rson]); Up(tree[1][root], tree[1][Lson], tree[1][Rson]);}Tnode query(int root, int L, int R, int x, int y){ if(x <= L && y >= R) return tree[0][root]; int mid = (L + R) >> 1, Lson = root << 1, Rson = root << 1 | 1; Down(root, Lson, Rson); tree[0][root].rev = tree[1][root].rev = false; if(y <= mid) return query(Lson, L, mid, x, y); else if(x > mid) return query(Rson, mid+1, R, x, y); else{ Tnode temp; Tnode temp1 = query(Lson, L, mid, x, y); Tnode temp2 = query(Rson, mid+1, R, x, y); Up(temp, temp1, temp2); return temp; }}int main(){ freopen("2201.in", "r", stdin); freopen("2201.out", "w", stdout); scanf("%d", &nG); while(nG --){ scanf("%d", &n); for(int i = 1; i <= n; i++) scanf("%d", &a[i]); build(1, 1, n); scanf("%d", &m); int a, b, c, d; for(int i = 1; i <= m; i++){ scanf("%d%d%d", &a, &b, &c); if(!a) update(1, 1, n, b, c); else{ scanf("%d", &d); int ans = 0; Tnode here[25]; for(int k = 1; k <= d; k++){ here[k] = query(1, 1, n, b, c); if(here[k].Tmax > 0){ ans += here[k].Tmax; flip(1, 1, n, here[k].Tmaxp1, here[k].Tmaxp2); } } for(int k = 1; k <= d; k++) if(here[k].Tmax > 0) flip(1, 1, n, here[k].Tmaxp1, here[k].Tmaxp2); printf("%d\n", ans); } } } return 0;}
之所以我不敢涉足
是因为回头亦是绝路
- SMOJ 2201 D (线段树)
- SMOJ 1980 XOR (线段树)
- 线段树D
- codeforces251/D/线段树
- codeforces 19D 线段树
- Gym 101617D 线段树
- CF 243D Cubes(线段树)
- CF 228D Zigzag(线段树)
- CF 19D Points(线段树)
- Codeforces 12D (线段树 树状数组
- codeforces 46D 线段树 区间合并
- CF 85D 五颗线段树
- Codeforces 19D Points 线段树+set
- CF 19D Points(线段树+set)
- [CodeforcesBeta Round #19 D. Points] (线段树)
- 【CodeForces】343D Water Tree 线段树
- CF-46D-Parking Lot(线段树)
- codeforces 46D 线段树区间合并
- 牛客网JavaScript在线编程题语言选择问题
- WEB前端-HF-HTML5Programming-笔记-CH3 事件与处理程序
- 线程安全的AtomicLong使用
- 假设检验(t-test)
- 隐藏多余cell
- SMOJ 2201 D (线段树)
- 数位DP专题小结--by sgx 数位DP专题小结--by sgx
- POJ 1852 Ants
- iOS系统的各种设备识别码
- OpenCV矩阵运算之顶点法向量计算
- Eclipse快捷键大全
- ContentProvider--共享文件(.jepg文件)
- laravel笔记-数据库(迁移)
- 自练题20170721