CF#310-E - Case of Chocolate-(set+贪心)/(线段树+离散化)/(隐式线段树)

来源:互联网 发布:汉邦网络摄像机默认ip 编辑:程序博客网 时间:2024/06/14 03:58

看了官解 是用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;

如果点j为向上吃(r=a), 那么只有一种情况,  点i会被j截断,则点i吃到r=a+1;

若点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");}elseif (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");}elseif (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;elseit--;  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;}




0 0