hdu 6375 百度之星 度度熊学队列

题目链接

Problem Description
度度熊正在学习双端队列,他对其翻转和合并产生了很大的兴趣。

初始时有 N 个空的双端队列(编号为 1 到 N ),你要支持度度熊的 Q 次操作。

①1 u w val 在编号为 u 的队列里加入一个权值为 val 的元素。(w=0 表示加在最前面,w=1 表示加在最后面)。

②2 u w 询问编号为 u 的队列里的某个元素并删除它。( w=0 表示询问并操作最前面的元素,w=1 表示最后面)

③3 u v w 把编号为 v 的队列“接在”编号为 u 的队列的最后面。w=0 表示顺序接(队列 v 的开头和队列 u 的结尾连在一起,队列v 的结尾作为新队列的结尾), w=1 表示逆序接(先将队列 v 翻转,再顺序接在队列 u 后面)。且该操作完成后,队列 v 被清空。
Input
有多组数据。

对于每一组数据,第一行读入两个数 N 和 Q。

接下来有 Q 行,每行 3~4 个数,意义如上。

N≤150000,Q≤400000

1≤u,v≤N,0≤w≤1,1≤val≤100000

所有数据里 Q 的和不超过500000
Output
对于每组数据的每一个操作②,输出一行表示答案。

注意,如果操作②的队列是空的,就输出−1且不执行删除操作。
Sample Input
2 10
1 1 1 23
1 1 0 233
2 1 1
1 2 1 2333
1 2 1 23333
3 1 2 1
2 2 0
2 1 1
2 1 0
2 1 1
Sample Output
23
-1
2333
233
23333
提示
由于读入过大,C/C++ 选手建议使用读入优化。
一个简单的例子:
void read(int &x){
char ch = getchar();x = 0;
for (; ch < '0' || ch > '9'; ch = getchar());
for (; ch >='0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
}
题意
实现双向队列,要求的功能有:维护N个双向队列,在首/尾部进行插入/删除,以及将一个队列顺序/逆序附到另一个队列尾部,并且清空原序列。
分析
为了避免双向队列颠倒的复杂度,其实完全可以忽略节点的先后顺序,把双向队列想象成一个所有节点入度出度都为1的连通图,那么对链表所有的操作,都可以看作是在图上的加边减边操作,因此,只需要维护每个节点的两条边就行了。
具体的来说,队列加点=连通图中新增一个节点并连一条边到指定的边界;队列删点=图删边;队列附加=两个连通图之间加一条边,连接两个边界点。
因为总是在队列首尾操作,也就是图的边界点,因此记录下每个连通图的两个边界,每次只需要找到图上边界点的相邻的点进行操作,并在操作完后,更新连通图的边界点。
注意
空队列不能被删除,但可以添加一个非空队列到他的后面

 代码

#include<stdio.h>
#include<memory.h>
int head[150005], tail[150005];
int n, q;
int id = 0;
//双向链表节点
struct thing
{
    int v;
    int t1, t2;//不必记录顺序
    thing() :v(0), t1(-1), t2(-1) {}
    void conn(int x) {
        if (t1 == -1)t1 = x;
        else t2 = x;
    }
    void brk(int x) {
        if (t1 == x)t1 = -1;
        else if (t2 == x)t2 = -1;
    }
}node[400005];

//头部插入
void qaddf(int qid, int nid) {
    if (head[qid] == -1) {
        head[qid] = nid;
        tail[qid] = nid;
    }
    else {
        int h = head[qid];
        node[nid].conn(h);
        node[h].conn(nid);
        head[qid] = nid;
    }
}

//尾部插入
void qadde(int qid, int nid) {
    if (head[qid] == -1) {
        head[qid] = nid;
        tail[qid] = nid;
    }
    else {
        int t = tail[qid];
        node[nid].conn(t);
        node[t].conn(nid);
        tail[qid] = nid;
    }
}

//头部删除
int delf(int qid) {
    int s = head[qid];
    if (s == -1)return -1;

    if (head[qid] == tail[qid]) {
        head[qid] = -1; tail[qid] = -1;
        return node[s].v;
    }

    int next = (node[s].t1 != -1 ? node[s].t1 : node[s].t2);
    node[next].brk(s);
    head[qid] = next;
    return node[s].v;
}

//尾部删除
int dele(int qid) {
    int s = tail[qid];
    if (s == -1)return -1;

    if (head[qid] == tail[qid]) {
        head[qid] = -1; tail[qid] = -1;
        return node[s].v;
    }

    int next = (node[s].t1 != -1 ? node[s].t1 : node[s].t2);
    node[next].brk(s);
    tail[qid] = next;
    return node[s].v;
}

//顺序连接
void linkf(int q1, int q2) {
    if (head[q2] == -1)return;
    if (head[q1] != -1) {
        node[tail[q1]].conn(head[q2]);
        node[head[q2]].conn(tail[q1]);
        tail[q1] = tail[q2];
        
    }
    else
    {
        head[q1] = head[q2];
        tail[q1] = tail[q2];
    }
    head[q2] = -1; tail[q2] = -1;
}

//逆序连接
void linke(int q1, int q2) {
    if(head[q2]==-1)return;
    if (head[q1] != -1) {
        node[tail[q1]].conn(tail[q2]);
        node[tail[q2]].conn(tail[q1]);
        tail[q1] = head[q2];
        
    }
    else
    {
        tail[q1] = head[q2];
        head[q1] = tail[q2];
    }
    head[q2] = -1; tail[q2] = -1;
}

//简易读外挂
void getn(int&x) {
    x = 0;
    char ch;
    do ch = getchar(); while (ch<'0' || ch>'9');
    do { x = x * 10 + ch - '0'; ch = getchar(); } while ('0' <= ch&&ch <= '9');
}

int main() {
    int ipt[4];
    while (~scanf("%d %d", &n, &q)) {
        id = 0;
        memset(head, -1, sizeof head);
        memset(tail, -1, sizeof tail);
        for (int i = 0; i<q; ++i) {
            getn(ipt[0]);
            switch (ipt[0]) {
            case 1://在队列ipt[1]中插入ipt[3]到头/尾部(ipt[2]=0/1)
                getn(ipt[1]); getn(ipt[2]); getn(ipt[3]);
                node[++id].v = ipt[3]; node[id].t1 = -1; node[id].t2 = -1;
                if (ipt[2] == 0) {
                    qaddf(ipt[1], id);
                }
                else {
                    qadde(ipt[1], id);
                }
                break;
            case 2://在队列ipt[1]中删除头/尾部(ipt[2]=0/1)
                getn(ipt[1]); getn(ipt[2]);
                if (ipt[2] == 0) {
                    printf("%d\n", delf(ipt[1]));
                }
                else {
                    printf("%d\n", dele(ipt[1]));
                }
                break;
            case 3://将队列ipt[2]正/反接到ipt[1]后面(ipt[3]=0/1)
                getn(ipt[1]); getn(ipt[2]); getn(ipt[3]);
                if (ipt[3] == 0)
                    linkf(ipt[1], ipt[2]);
                else
                    linke(ipt[1], ipt[2]);
                break;
            default:
                break;
            }
        }
    }
}
#define tree \
\
*\
**\
***\
||

 

posted @ 2018-08-11 17:50  会打表的toby  阅读(402)  评论(0编辑  收藏  举报