HDU3410 Passing the Message (單調隊列,線段樹可解)

Passing the Message

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 534    Accepted Submission(s): 333


Problem Description
What a sunny day! Let’s go picnic and have barbecue! Today, all kids in “Sun Flower” kindergarten are prepared to have an excursion. Before kicking off, teacher Liu tells them to stand in a row. Teacher Liu has an important message to announce, but she doesn’t want to tell them directly. She just wants the message to spread among the kids by one telling another. As you know, kids may not retell the message exactly the same as what they was told, so teacher Liu wants to see how many versions of message will come out at last. With the result, she can evaluate the communication skills of those kids.
Because all kids have different height, Teacher Liu set some message passing rules as below:

1.She tells the message to the tallest kid.

2.Every kid who gets the message must retell the message to his “left messenger” and “right messenger”.

3.A kid’s “left messenger” is the kid’s tallest “left follower”. 

4.A kid’s “left follower” is another kid who is on his left, shorter than him, and can be seen by him. Of course, a kid may have more than one “left follower”. 

5.When a kid looks left, he can only see as far as the nearest kid who is taller than him.

The definition of “right messenger” is similar to the definition of “left messenger” except all words “left” should be replaced by words “right”. 

For example, suppose the height of all kids in the row is 4, 1, 6, 3, 5, 2 (in left to right order). In this situation , teacher Liu tells the message to the 3rd kid, then the 3rd kid passes the message to the 1st kid who is his “left messenger” and the 5th kid who is his “right messenger”, and then the 1st kid tells the 2nd kid as well as the 5th kid tells the 4th kid and the 6th kid. 
Your task is just to figure out the message passing route.
 

Input
The first line contains an integer T indicating the number of test cases, and then T test cases follows.
Each test case consists of two lines. The first line is an integer N (0< N <= 50000) which represents the number of kids. The second line lists the height of all kids, in left to right order. It is guaranteed that every kid’s height is unique and less than 2^31 – 1 .
 

Output
For each test case, print “Case t:” at first ( t is the case No. starting from 1 ). Then print N lines. The ith line contains two integers which indicate the position of the ith (i starts form 1 ) kid’s “left messenger” and “right messenger”. If a kid has no “left messenger” or “right messenger”, print ‘0’ instead. (The position of the leftmost kid is 1, and the position of the rightmost kid is N)
 

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

 大致題意:一共有n個數,對於其中每個數存在"left messenger"和"right messenger"。leftmessenger:該數到其左側第一個大於該數的數爲止的區域中最大的數,若不存在這樣的數那麼left messenger記爲0。right messenger定義類似。題目需要求出數列中每個數的left messenger和right messenger。
 思路:使用單調隊列,從左往右添加元素,對於第K個元素,爲將該元素加入隊列而出隊的最大元素的下標即爲K元素的left messenger 的下標。從右往左添加元素可求得right messenger

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 50005;

struct Node
{
    int val,pos;
};

int a[N];
Node tmp[N];
int n;
int ansL[N],ansR[N];

void solve()
{
    int tail;
    tail = 0;
    for (int i=1;i<=n;i++)
    {
        bool flag = false;
        while (tail > 0 && tmp[tail-1].val < a[i])
        {
            tail--;
            flag = true;
        }
        ansL[i] = flag ? tmp[tail].pos : 0;
        tmp[tail++].pos = i;
        tmp[tail-1].val = a[i];
    }

    tail = 0;
    for (int i=n;i>=1;i--)
    {
        bool flag = false;
        while (tail > 0 && tmp[tail-1].val < a[i])
        {
            tail--;
            flag = true;
        }
        ansR[i] = flag ? tmp[tail].pos : 0;
        tmp[tail++].pos = i;
        tmp[tail-1].val = a[i];
    }

    for (int i=1;i<=n;i++)
    {
        printf("%d %d\n",ansL[i],ansR[i]);
    }
}

int main()
{
    int T;
    scanf("%d",&T);
    for (int cnt=1; cnt<=T; cnt++)
    {
        scanf("%d",&n);
        for (int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
        }
        printf("Case %d:\n",cnt);
        solve();
    }
    return 0;
}

線段樹AC代碼(瞎眼預警)
#include<iostream>
#include<cstdio>
#include<cstring>
#define lson node*2,l,(r+l)/2
#define rson node*2+1,(l+r)/2+1,r
using namespace std;
const int MAX = 50005;

struct Node
{
    int pos;
    int n;
}segTree[MAX*4];


int lef[MAX],rig[MAX];
int arr[MAX];
int ansl[MAX],ansr[MAX];
int k;

void build(int node,int l,int r)
{
    if (l == r)
    {
        segTree[node].pos = l;
        segTree[node].n = arr[l];
    }
    else
    {
        build(lson);
        build(rson);
        if (segTree[node*2].n > segTree[node*2+1].n)
        {
            segTree[node] = segTree[node*2];
        }
        else
        {
            segTree[node] = segTree[node*2+1];
        }
    }
}

int query(int node,int l,int r,int s,int e)
{
    if (s>e)
        return 0;
    if (r<s || l>e) return -1;
    else if (r<=e && l>=s) return segTree[node].pos;
    else
    {
        int n1 = query(lson,s,e);
        int n2 = query(rson,s,e);
        if (n1==-1) return n2;
        else if (n2==-1) return n1;
        else
        {
            if (arr[n1] > arr[n2]) return n1;
            else
                return n2;
        }
    }
}

void solve(int n,int p)
{
    if (p==-1)
    {
        ansl[n] = query(1,1,k,lef[n]+1,n-1);
        ansr[n] = query(1,1,k,n+1,rig[n]-1);
    }
    else
    {

        if (n<p)
        {
            lef[n] = lef[p];
            rig[n] = p;
            ansl[n] = query(1,1,k,lef[p]+1,n-1);
            ansr[n] = query(1,1,k,n+1,p-1);
        }
        else
        {
            lef[n] = p;
            rig[n] = rig[p];
            ansl[n] = query(1,1,k,p+1,n-1);
            ansr[n] = query(1,1,k,n+1,rig[p]-1);
        }
    }
    if (ansl[n])
        solve(ansl[n],n);
    if (ansr[n])
        solve(ansr[n],n);
}

int main()
{
    int T;
    scanf("%d",&T);
    for (int cnt=1; cnt<=T; cnt++)
    {
        scanf("%d",&k);
        for (int i=1;i<=k;i++)
        {
            scanf("%d",&arr[i]);
        }
        build(1,1,k);
        int t = segTree[1].pos;
        lef[t] = 0; rig[t] = k+1;
        solve(t,-1);
        printf("Case %d:\n",cnt);
        for (int i=1;i<=k;i++)
        {
            printf("%d %d\n",ansl[i],ansr[i]);
        }
    }

    return 0;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章