zoj3963

思路分析:若前面的维护的数已按小到大排好序,每次找到左边第一个小于等于素该元的数插入,如果标记插入次数>=2,

                  则从中删除。用set或权值线段树维护即可。

!!!!nlog(n)的算法TLE了很多发,加上各种读优化仍旧TLE,懵逼逼。。。不知羞耻地上网看了别人的代码,发现T在了

 memset 上面,把 sizeof()改为  4*n+4就过了。。。 涨姿势了。。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<vector>
#include<set>
using namespace std;
struct Q{
    int v,x;
}A[100010];
vector<int>g[100010];
set<int>s;
set<int>::iterator it;
int vis[100010],bel[100010],B[100010],cnt[100010];
int main(){
    int t,i,j,n;
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        memset(vis,0,4*n+4);
        memset(bel,0,4*n+4);
        memset(cnt,0,4*n+4);
        for(i=0;i<=n;i++) g[i].clear();
        s.clear();
        for(i=1;i<=n;i++){
            scanf("%d",&A[i].v);
            cnt[A[i].v]++;
        }
        for(i=1;i<=n;i++) cnt[i]+=cnt[i-1];
        for(i=n;i>=1;i--){
                A[i].x=cnt[A[i].v]--;
                B[A[i].x]=i;
        }
        int k=0;
        for(i=1;i<=n;i++){
            if(s.size()==0||*s.begin()>A[i].x) bel[i]=k++;
            else{
                it=s.lower_bound(A[i].x);
                it--;
                bel[i]=bel[B[*it]];
                vis[*it]++;
                if(vis[*it]==2) s.erase(*it);
            }
            s.insert(A[i].x);
        }
        for(i=1;i<=n;i++){
            g[bel[i]].push_back(i);
        }
        printf("%d\n",k);
        for(i=0;i<k;i++){
            printf("%d",g[i].size());
            for(j=0;j<g[i].size();j++) printf(" %d",g[i][j]);
            printf("\n");
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/guogai13/article/details/82230281