2018HDU多校第一场1004 HDU6301Distinct Values

                                                                                              Distinct Values
                                                    Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
                                                                   Total Submission(s): 2107    Accepted Submission(s): 666


Problem Description
Chiaki has an array of n positive integers. You are told some facts about the array: for every two elements ai and aj in the subarray al..r (l≤i<j≤r), ai≠aj holds.
Chiaki would like to find a lexicographically minimal array which meets the facts.

 

Input
There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:

The first line contains two integers n and m (1≤n,m≤105) -- the length of the array and the number of facts. Each of the next m lines contains two integers li and ri (1≤li≤ri≤n).

It is guaranteed that neither the sum of all n nor the sum of all m exceeds 106.
 

Output
For each test case, output n integers denoting the lexicographically minimal array. Integers should be separated by a single space, and no extra spaces are allowed at the end of lines.

 

Sample Input
3
2 1
1 2
4 2
1 2
3 4
5 2
1 3
2 4

 

Sample Output
1 2
1 2 1 2
1 2 3 1 1

题意:n个数,m个区间,每个区间内数字互不相同,问字典序最小的n个数.

思路:可以将这n个数看成数轴,上面有些点是区间起点或者终点,并且只是一个区间的起点或终点(这就需要我们把区间去重,只留下最大的)。还需要用一个优先队列来弹出我们填的数,优先队列可是每次数字尽量小。然后从左往右走,从起点开始依次从队列弹出数字,然后遇到终点时,从刚刚起点开始往右走,直到遇到下一个起点或者到达当前点为止,把路过的数压入优先队列。

代码:

#include<bits/stdc++.h>
using namespace std;

const int maxn = 1e5+5;

struct edge
{
    int l,r;
    int num;
} line[maxn];

bool cmp(edge x,edge y)
{
    if(x.l == y.l)
        return x.r> y.r;
    return x.l< y.l;
}

int n,m;
int ans[maxn],a[maxn],b[maxn];

int main()
{
    int t;
    cin>>t;
    
    while(t--)
    {
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
        memset(ans,0,sizeof(ans));
        
        scanf("%d %d",&n,&m);
        for(int i = 1;i<= m;i++)
        {
            scanf("%d %d",&line[i].l,&line[i].r);
            line[i].num = i;//给每个区间标号 
        }
        
        sort(line+1,line+m+1,cmp);
        
        int maxr = 0;
        for(int i = 1;i<= m;i++)//把区间起点、终点标在a,b数组上,大区间包含小区间的 情况直接去掉小区间 
        {
            if(line[i].r<= maxr) continue;
            if(a[line[i].l]) continue;
            a[line[i].l] = i;
            b[line[i].r] = i;
            maxr = line[i].r;
        }
        
        priority_queue<int,vector<int>,greater<int> >q;//存储可用数字,小的在前 
        for(int i = 1;i<= n;i++)
            q.push(i);
        
        int i = 1,j;
        for(i = 1;i<= n&&a[i] == 0;i++) ans[i] = 1;//把初始没有要求的地方都赋值1 
		for(;i<= n;i++)
        {
            ans[i] = q.top();
            q.pop();
            if(b[i])
            {
                for(j = line[b[i]].l;j<= i&&(a[j] == 0||a[j] == b[i]);j++)
                    q.push(ans[j]);
                if(j> i)
                {
                    while(j<= n&&a[j] == 0)//把没有要求的地方都赋值1
                    {
                        ans[j] = 1;
                        j++;
                    }
                    i = j-1;
                }
            }
        }
        
        for(i = 1;i< n;i++)
            printf("%d ",ans[i]);
        printf("%d\n",ans[n]);
    }
    
    return 0;
}

猜你喜欢

转载自blog.csdn.net/nka_kun/article/details/81182942
今日推荐