CodeForces 555C(set or 线段树)

题目大意:给一个巧克力,把副对角线(参照线代)下方的先都吃掉,然后每次给出一个询问,从对角线出发,要么向上,要么向左,吃到已经吃过的地方或者边缘为止,输出每次能吃多少小格巧克力。

思路:官方题解是线段树做得(我暂时还不会),然后在网上找到了一个超级简短的代码,是用set做的,但是我看了感觉有3个小时才基本看懂(汗。。。果然还是太弱了)。首先这个代码的离散化几乎没有多余的代码(佩服佩服),最开始看的时候有点搞不清楚方向。这个问题首先的突破点是:对于向上吃的操作,能够影响到其高度的之前的操作起始点应该是在这个操作的起始点右面的,而理解这个做法的最关键的一点是事实上能够影响的操作是最为靠近当前点的右面的点。也就是说当前这个点能够达到的最高点和最近右边的这个点能达到的最高点是一致的。如果右面这个点是向左,那么显然,如果右面这个点是向上,那么这个点得出的高度是考虑了更右面的所有点得出的,自然也适用于当前点。在代码里每次读入xy后,如果是向上,那么更新y,否则更新x,用set完成最近点的查找。

代码参照:http://blog.csdn.net/u011580493/article/details/46701113

又及:在cf的网站上看了下代码,个个都短得可以。。。。基本都是set和map,,没几个用线段树的。。。。。

#include<bits/stdc++.h>

#define pb push_back

using namespace std;

typedef long long ll;

typedef pair<int,int> P;

const int maxv=2e5+50;

int x[maxv],y[maxv];

set<P> s;

set<P>::iterator it;

int n,q;

char ch[2];

int main(){

    ///freopen("/home/files/CppFiles/in","r",stdin);

    cin>>n>>q;

    s.insert(P(0,0));

    s.insert(P(n+1,q+1));

    for(int i=1;i<=q;i++){

        scanf("%d%d%s",&x[i],&y[i],ch);

        if(ch[0]=='U'){

            it=s.lower_bound(P(y[i],-1));

            if(it->first>y[i]) it--;

        }else{

            it=s.upper_bound(P(y[i],-1));

        }

        if(it->first==y[i]){

            puts("0");

            continue;

        }

        s.insert(P(y[i],i));

        if(ch[0]=='U'){

            printf("%d\n",y[i]-y[it->second]);

            y[i]=y[it->second];

        }else{

            printf("%d\n",x[i]-x[it->second]);

            x[i]=x[it->second];

        }

    }

    return 0;

}
View Code

计划有时间写一下线段树版本。

你可能感兴趣的:(codeforces)