【CoderForces】#296 Div2 C(线段树+set)

来源:互联网 发布:淘宝售后术语大全 编辑:程序博客网 时间:2024/06/08 13:17
/*这边可以用线段树的原因在于,在水平方向上的最大值,与竖直方向上的最大值是相对应的,也就是说我们只需要求出了水平和竖直方向的最大值,然后相乘就可以了,一开始一直没想通这个,以为是不是对应的,那样的话就没法求了。线段树思路:两个线段树分别计算出水平方向和竖直方向的最大值,最后相乘就可以了。这么就涉及到区间的计算,所以需要两个数组来存水平方向和竖直方向的分割线。最后更新就可以了。也可以用其他的做法。另外一种方法也是如上求出边界,然后算出间隔,加入到容器当中,最后水平方向和竖直方向最大的相乘就可以了。*/#define _CRT_SECURE_NO_WARNINGS#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<set>using namespace std;#define MAX 200002#define ls rt<<1#define rs ls|1#define m (l+r)>>1int sum1[MAX << 2];int sum2[MAX << 2];int col1[MAX << 2];int col2[MAX << 2];set<int> posx;set<int> posy;void ups(int *col,int *sum,int rt){if (col[rt] + 1){col[ls] = col[rt];col[rs] = col[rt];sum[rs] = col[rt];sum[ls] = col[rt];col[rt] = -1;}}void uprt( int *sum, int rt){sum[rt] = max(sum[ls], sum[rs]);}void updata(int *sum, int *col, int L, int R, int c, int l, int r, int rt){if (L <= l&&r <= R){col[rt] = c;sum[rt] = c;return;}ups(col, sum, rt);int mid = m;if (L <= mid)updata(sum, col, L, R, c, l, mid, ls);if (mid < R)updata(sum, col, L, R, c, mid + 1, r, rs);uprt(sum, rt);}int main(){int w, h, n;while (~scanf("%d%d%d%*c", &w, &h, &n)){posx.clear();posy.clear();memset(col1, -1, sizeof(col1));memset(col2, -1, sizeof(col2));updata(sum1, col1, 0, w, w, 0, w, 1);updata(sum2, col2, 0, h, h, 0, h, 1);posx.insert(0);posx.insert(w);posy.insert(0);posy.insert(h);char str[5];int a;set<int>::iterator l, r, mid;for (int i = 0; i < n; i++){scanf("%s%d", str, &a);if (str[0] == 'H'){posy.insert(a);l = posy.find(a);mid = l;l--;r = mid;r++;updata(sum2, col2, *l, *mid, (*mid) - (*l), 0, h, 1);updata(sum2, col2, *mid + 1, *r, *r - *mid, 0, h, 1);}else{posx.insert(a);l = posx.find(a);mid = l;l--;r = mid;r++;updata(sum1, col1, *l, *mid, (*mid) - (*l), 0,w, 1);updata(sum1, col1, *mid + 1, *r, *r - *mid , 0, w, 1);}printf("%lld\n", ((long long)sum1[1]) * sum2[1]);}}}



转载一个别人的其他做法:

/*这边可以用线段树的原因在于,在水平方向上的最大值,与竖直方向上的最大值是相对应的,也就是说我们只需要求出了水平和竖直方向的最大值,然后相乘就可以了,一开始一直没想通这个,以为是不是对应的,那样的话就没法求了。线段树思路:两个线段树分别计算出水平方向和竖直方向的最大值,最后相乘就可以了。这么就涉及到区间的计算,所以需要两个数组来存水平方向和竖直方向的分割线。最后更新就可以了。也可以用其他的做法。*/#define _CRT_SECURE_NO_WARNINGS#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<set>using namespace std;#define MAX 200002#define ls rt<<1#define rs ls|1#define m (l+r)>>1int sum1[MAX << 2];int sum2[MAX << 2];int col1[MAX << 2];int col2[MAX << 2];set<int> posx;set<int> posy;void ups(int *col,int *sum,int rt){if (col[rt] + 1){col[ls] = col[rt];col[rs] = col[rt];sum[rs] = col[rt];sum[ls] = col[rt];col[rt] = -1;}}void uprt( int *sum, int rt){sum[rt] = max(sum[ls], sum[rs]);}void updata(int *sum, int *col, int L, int R, int c, int l, int r, int rt){if (L <= l&&r <= R){col[rt] = c;sum[rt] = c;return;}ups(col, sum, rt);int mid = m;if (L <= mid)updata(sum, col, L, R, c, l, mid, ls);if (mid < R)updata(sum, col, L, R, c, mid + 1, r, rs);uprt(sum, rt);}int main(){int w, h, n;while (~scanf("%d%d%d%*c", &w, &h, &n)){posx.clear();posy.clear();memset(col1, -1, sizeof(col1));memset(col2, -1, sizeof(col2));updata(sum1, col1, 0, w, w, 0, w, 1);updata(sum2, col2, 0, h, h, 0, h, 1);posx.insert(0);posx.insert(w);posy.insert(0);posy.insert(h);char str[5];int a;set<int>::iterator l, r, mid;for (int i = 0; i < n; i++){scanf("%s%d", str, &a);if (str[0] == 'H'){posy.insert(a);l = posy.find(a);mid = l;l--;r = mid;r++;updata(sum2, col2, *l, *mid, (*mid) - (*l), 0, h, 1);updata(sum2, col2, *mid + 1, *r, *r - *mid, 0, h, 1);}else{posx.insert(a);l = posx.find(a);mid = l;l--;r = mid;r++;updata(sum1, col1, *l, *mid, (*mid) - (*l), 0,w, 1);updata(sum1, col1, *mid + 1, *r, *r - *mid , 0, w, 1);}printf("%lld\n", ((long long)sum1[1]) * sum2[1]);}}}


0 0
原创粉丝点击