看了官解 是用2个线段树,一个维护横坐标,一个维护纵坐标(要离散化).......还有后面的隐式线段树还没看
后来看到另一种方法、仔细分析下题目的操作,其实很简单。
用两个set维护 横纵坐标、分别叫row(水平方向)、high(竖直)
分析两种情况:
对于(xi,n+1-xi),若是向上吃,能够影响它的操作(xj,n+1-xj)一定是右边第一个点,
若点i右边有点:
如果点j为向上吃,如果j能吃到x=0处,则表示点i和j之间无L操作,则点i也吃到x=0
如果点j为向上吃,但是只吃到x=b处,则表示点i和j都会被一操作L(x=b-1)截断,所以点i也吃到x=b;
如果点j为向左吃(吃到x=b),那么只有一种情况, 点i会被j截断,点i吃到x=b+1处
若点i右边无点:
点i吃到0处;
对于向左的(xi,n+1-xi),能够影响它的操作(xj,n+1-xj)一定是左边第一个点,
如果点i左边有点:
如果点j为向左吃,如果j能吃到x=0处,则表示点i和j之间无U操作,则点i也吃到x=0
如果点j为向左吃,但是只吃到r=a处,则表示点i和j都会被一操作u(r=a-1)截断,所以点i也吃到r=a;
若点i左边无点:
点i吃到0处;
然后就是实现了,注意,如果某个坐标已经出现过了,再次出现吃的巧克力数量为0;
特别要注意的是 在各个情况下 对begin和end的判断,否则容易指针越界
--------------------------
UPDATA:发现很多情况都可以合并在一起,只用一个set维护即可,每次判断是否存在第一个r坐标大于等于点i的点j即可,如果存在,必定受其影响,不存在,必定吃到边界结束;
代码:
#include <cstdio>
#include <cmath>
#include <iostream>
#include <set>
#include <algorithm>
using namespace std;
struct node
{
int r,c;
int last;
char ty;
node(){}
node(int a,int b,int cc,char t)
{
r=a;
c=b;
last=cc;
ty=t;
}
bool operator <(const node&b)const
{
return r<b.r;
}
bool operator ==(const node&b)const
{
return r==b.r&&c==b.c;
}
};
int cmp(node a,node b)
{
return a.r>b.r;
}
set<node> sb;
set<node>::iterator it;
int main()
{
int i,j;
int n,m;
int a,b;
char op;
scanf("%d%d",&n,&m);
for (i=1;i<=m;i++)
{
node tp;
scanf("%d %d %c",&a,&b,&op);
if (op=='U')
{
tp.r=a;
it=sb.lower_bound(tp);
if (it->r==a)
{
printf("0\n");
}
else
if (it==sb.end())
{
sb.insert(node(a,b,1,op));
printf("%d\n",b);
}
else
{
if (it->ty=='U')
{
// printf("%d\n",it->last);
sb.insert(node(a,b,it->last,op));
printf("%d\n",b-it->last+1);
}
else
{
sb.insert(node(a,b,it->c+1,op));
printf("%d\n",b-it->c);
}
}
}
else
{
tp.r=a;
it=sb.lower_bound(tp);
if (it->r==a)
{
printf("0\n");
}
else
if (it==sb.begin())
{
sb.insert(node(a,b,1,op));
printf("%d\n",a);
}
else
{
it--;
if (it->ty=='L')
{
sb.insert(node(a,b,it->last,op));
printf("%d\n",a-it->last+1);
}
else
{
sb.insert(node(a,b,it->r+1,op));
printf("%d\n",a-it->r);
}
}
}
}
return 0;
}
-------------------------
以下是上一种方法的写法:
#include <cstdio>
#include <cmath>
#include <iostream>
#include <set>
#include <algorithm>
using namespace std;
struct node
{
int r,c;
int last;
node(){}
node(int a,int b,int cc)
{
r=a;
c=b;
last=cc;
}
bool operator <(const node&b)const
{
return r<b.r;
}
bool operator ==(const node&b)const
{
return r==b.r&&c==b.c;
}
};
int cmp(node a,node b)
{
return a.r>b.r;
}
set<node> row;
set<node> high;
set<node>::iterator it,nx;
int main()
{
int i,j;
int n,m;
int a,b;
char op;
scanf("%d%d",&n,&m);
for (i=1;i<=m;i++)
{
node tp;
scanf("%d %d %c",&a,&b,&op);
if (op=='U')
{
if (high.find(node(a,b,0))!=high.end()||row.find(node(a,b,0))!=row.end()) {
printf("0\n");
continue;
}
tp.r=a;
it=row.lower_bound(tp);
nx=high.lower_bound(tp);
if ( nx==high.end()) //如果有不存在L操作在点i的右边,那么必定可以吃到0为止
{
row.insert(node(a,b,0));
printf("%d\n",b);
}
else //以下情况必定点i右边有L操作
{
int not1=0;
if (it==row.end()) //右边有L时,如果it==end,也就是点i右边不存在U操作,所以一定被L操作截断
not1=1;
if (not1||(nx->r<it->r)) //如果既有U也有L,但是L操作比较靠近点i, 点i一定被L操作截断
{
// printf("%d\n",nx->c);
row.insert(node(a,b,nx->c+1));
printf("%d\n",b-nx->c);
}
else //如果既有U也有L,但是U操作比较靠近点i, 点i能吃到最远处与该u操作一样远
if (nx->r>it->r)
{
if (it->last==0)
{
row.insert(node(a,b,0));
printf("%d\n",b);
}
else
{
row.insert(node(a,b,it->last));
printf("%d\n",b-it->last+1);
}
}
}
}
else // 'L'
{
if (high.find(node(a,b,0))!=high.end()||row.find(node(a,b,0))!=row.end())
{
printf("0\n");
continue;
}
tp.r=a;
it=high.lower_bound(tp);
nx=row.lower_bound(tp);
if (nx==row.begin()) //如果U操作全在点i的右边,那么点i的L操作必然能吃到0;
{
high.insert(node(a,b,0));
printf("%d\n",a);
}
else //以下情况必定点i左边有U操作
{
int not1=0;
if (it==high.begin()) //左边有U时,如果it==begin,也就是点i左边不存在L操作,所以一定被U操作截断
not1=1;
else
it--;
nx--; //lowerbound得到的是大于等于的第一个,所以要nx--得到小于的第一个
if (not1||(nx->r>it->r ) ) //如果既有U也有L,但是U操作比较靠近点i, 点i一定被U操作截断
{
// printf("%d\n",nx->r);
high.insert(node(a,b,nx->r+1));
printf("%d\n",a-nx->r);
}
else //如果既有U也有L,但是L操作比较靠近点i, 点i能吃到最远处与该L操作一样远
if ( nx->r<it->r )
{
if (it->last==0)
{
high.insert(node(a,b,0));
printf("%d\n",a);
}
else
{
high.insert(node(a,b,it->last));
printf("%d\n",a-it->last+1);
}
}
}
}
}
return 0;
}