1. 程式人生 > >2018浙江省賽 E題 ZOJ4028 LIS

2018浙江省賽 E題 ZOJ4028 LIS

LIS
Time Limit: 1 Second      Memory Limit: 65536 KB      Special Judge

Sample Input

4
6
1 2 3 2 4 3
0 5
2 4
3 3
1 2
3 5
1 5
5
1 2 1 3 1
100 200
200 300
200 400
400 500
100 500
7
1 2 3 1 1 4 2
0 3
0 3
0 3
0 3
0 3
0 3
0 3
2
1 1
1 2
2 3

Sample Output

1 2 3 2 5 3
200 300 200 500 200
0 1 2 0 0 3 1
2 2
【題意】給定一個數組f[],f[i]表示以第i個字元為終點的最長上升子序列長度,然後輸入n行,每行有一個區間[l,r],表示第i個數字的取值範圍,輸出符合條件的任意一組序列,保證有解。
【思路】對於給定的f[]按照大小排序,大小相等按照下標從小到大排序,ans[]儲存最後要輸出的答案。很明顯,對於f[i]越小且越靠前的值,應該給ans[i]的值應大於下標i小且距離i最近的長度為f[i]-1的元素,並且在區間[l,r]能取的最小值;同時,對於最長上升子序列長度相等的元素來說,下標大的元素的值應該小於等於下標小的值。
【程式碼如下】
#include <bits/stdc++.h>
using namespace std;

const int N = 1e5+10;
struct node{
    int f,l,r,indx;
}p[N];
vector<int>vct[N];
int t,n,ans[N],a[N];

bool cmp(node A, node B){
    if(A.f == B.f) return A.indx < B.indx;
    return A.f < B.f;
}

int main(){
    scanf("%d",&t);
    while(t --){
        scanf("%d",&n);
        for(int i = 0; i <= n+1; i ++) vct[i].clear();
        for(int i = 1; i <= n; i ++) scanf("%d",&p[i].f),p[i].indx = i;
        for(int i = 1; i <= n; i ++) scanf("%d%d",&p[i].l,&p[i].r),a[i]=p[i].r;
        sort(p+1,p+n+1,cmp);
        for(int i = 1; i <= n; i ++){
            int len = p[i].f;
            int l = p[i].l,r=p[i].r;
            int t=-1;
            if(len==1){
                ans[p[i].indx] = l;
                int lena = vct[len].size();
                for(int j = lena-1; j >= 0; j --){
                    int tt = vct[len][j];
                    if(l > ans[tt]) ans[tt]=l;
                    else break;
                }
            }
            else{
                int in = lower_bound(vct[len-1].begin(),vct[len-1].end(),p[i].indx) - vct[len-1].begin()-1;
                int tt = vct[len-1][in];

                if(ans[tt] >= l && ans[tt] < r) t = ans[tt]+1;
                else if(ans[tt] < l) t = l;

                int lena = vct[len].size();
                for(int j = lena-1; j >= 0; j --){
                    int x = vct[len][j];
                    if(ans[x] < t){
                        ans[x] = min(t,a[x]);
                    }
                    else break;
                }
            }
            if(t>0) ans[p[i].indx] = t;
            vct[len].push_back(p[i].indx);
        }
        for(int i = 1; i <= n; i ++){
            if(i>1) printf(" ");
            printf("%d",ans[i]);
        }
        printf("\n");
    }
    return 0;
}