您的位置:首页 > 其它

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

2015-03-18 19:28 323 查看
/*
这边可以用线段树的原因在于,在水平方向上的最大值,与竖直方向上的最大值是相对应的,也就是说我们只需要求出了水平和竖直方向的最大值,然后相乘就可以了,
一开始一直没想通这个,以为是不是对应的,那样的话就没法求了。
线段树思路:两个线段树分别计算出水平方向和竖直方向的最大值,最后相乘就可以了。
这么就涉及到区间的计算,所以需要两个数组来存水平方向和竖直方向的分割线。最后更新就可以了。
也可以用其他的做法。
另外一种方法也是如上求出边界,然后算出间隔,加入到容器当中,最后水平方向和竖直方向最大的相乘就可以了。
*/
#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)>>1
int 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)>>1
int 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]);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: