cf #344 div2 -C. Report

为什么我感觉这道题其实真的有点难,但还是有很多人过, 还是我太弱了!!!
题意:给一个长度为n (n<200000) 的数列。 然后m次操作,每一次操作输入 t,r。 对前r个操作,做递减或者递增的排序!

2016-5-10回顾:
如果先对 前n个操作,再对前n+1 (或者>n)个操作,肯定第一次操作是可以跳过的,
所以我们可以筛选出一个操作长度的递减序列 操作即可。 但这样有可能T的,很容易被数据卡掉。
再想可以发现,其实每一次排序都确定了一些值,还是筛选出 m’ 个有效操作,记录每一个操作从尾部的i
开始,记录这次操作是从小到大还是从大到小, 然后开一个全局表示最小值minn(从1开始),最大值maxn(从n 开始),然后从i - —-j (下一次操作开始的地方), 依次填入minn或则maxn 并逐个递增,减(根据这一次操作排列方式来),,, 理论ac 应该是没问题的。 简单题,不难

注意: 我觉得这个地方题目并没有表达清楚,我一开始以为只要是非减就行了,但其实貌似题目的输出,非减就代表了递增!!!

然后呢m次操作之后,会得到一个新的序列,输出这个序列就好了。
一开始的想法: 如果有操作i,j,存在i < j,并且ri < rj ,那么不管他是不是递增还是递减排列,操作i都是一次无效的操作。
然后就开始写排序了,这样很容易被某一组数据卡死超时,这种想法还是太水了~,
仔细想想上面的分析之后不难发现一个最最关键的地方:
有效操作呈这样的分布:
…的长度代表某次操作的r[i]的大小。
……………………………………………………….
…………………………………………………..
……………………………………………..
…………………………………………
……………………………… ……
………………………………..
………………………
………………..
也就是:有效操作的序号 i,j 满足i < j,则 r[i] > r[j];
再想一下一个小方法这道题其实就是一道水题了:
我们可以得到所有操作的最大值maxn ,也就是所有操作的是围绕着前maxn 个数来排序。
那么我们可以先把这前maxn个数从小到大排好序;
如果第一个有效操作 是递增:

………………………………………………………………. 第一个有效操作
…………………………………………….. *********** 第二个有效操作
—————————————|—————-| 中间这一段 是不是就是最大的几个值??
若第一个有效操作是递减,拿着一段就是最小的几个值!

讲到这里应该就很明显了:

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#define mem(a) memset(a,0,sizeof(a))
#define pfn printf("\n")
#define sf scanf
#define pf printf
#define fr(i,n) for(int i=0;i<n;i++)
#define INF 0x7fffffff //INT_MAX
#define inf 0x3f3f3f3f //
const double PI = acos(-1.0);
const double e = exp(1.0);
template<class T> T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }
template<class T> T lcm(T a, T b) { return a / gcd(a, b) * b; }
using namespace std;
#define lson l , mid , rt << 1
#define rson mid + 1 , r , rt << 1 | 1
using namespace std;
#define rep(i,s,t) for(int i=int(s); i<int(t); i++)
#define mst(A,k) memset(A,k,sizeof(A))
int Scan()
{
    int res = 0, ch, flag = 0;

    if((ch = getchar()) == '-')             //判断正负
        flag = 1;
    else if(ch >= '0' && ch <= '9')         //得到完整的数
        res = ch - '0';
    while((ch = getchar()) >= '0' && ch <= '9' )
        res = res * 10 + ch - '0';
    return flag ? -res : res;
}

int a[200005];
int t[200005],r[200005];
int flag[200005];
int maxn;
int num[200005];
int ans[200005];
bool cmp(int a,int b){
    return a<b;
}

int main(){
    int n,m;
    //freopen("1.txt","r",stdin);
    while(~scanf("%d %d",&n,&m)){
        mem(flag);
        maxn=0;
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        for(int i=1;i<=m;i++){
            scanf("%d %d",&t[i],&r[i]);
            flag[r[i]]=t[i]; //用flag保存该数组是递增还是递减
            num[r[i]]=i;    //保存每一步操作处理前maxn个。
            maxn=max(maxn,r[i]);
        }
        sort(a+1,a+maxn+1,cmp);
        int ll=1,rr=maxn;
        int xuhao=0;
        int now_flag;   //保存flag值
        for(int i=maxn;i>0;i--){
            if(flag[i] && num[i]>xuhao){   // 如果存在 对于前i个数的 操作
                xuhao=num[i];  //num必须在上一次的序列后面,才会进行操作
                now_flag=flag[i];
            }
            // 如果不存在,那么之前的那一次操作依然会对往后的几个数值有影响
            if(now_flag==2){
                ans[i]=a[ll];
                ll++;
            }
            else{
                ans[i]=a[rr];
                rr--;
            }
        }
        for(int i=1;i<=maxn;i++)
            i==1?printf("%d",ans[i]):printf(" %d",ans[i]);
        for(int i=maxn+1;i<=n;i++)
            printf(" %d",a[i]);
        printf("\n");
    }
    return 0;
}

你可能感兴趣的:(cf #344 div2 -C. Report)