jzoj 5794. [2018提高组] 模拟A组&省选 旅行 LCT

Description

悠悠岁月,不知不觉,距那传说中的pppfish晋级泡泡帝已是过 去数十年。数十年 中,这颗泡泡树上,也是再度变得精彩,各种泡泡 天才辈出,惊艳世人,然而,似乎 不论后人如何的出彩,在他们的头 顶之上,依然是有着一道身影而立。 泡泡帝,pppfish。 现在,pppfish即将带着被自己收服的无数个泡泡怪前往下一个 空间,而在前往下 一个空间的道路上,有N个中转站,和M条空间虫洞连接中转站(双向通道,可有重 边,可有环),然而,通过虫洞 是要一定的条件的,pppfish将手下所有泡泡怪编号为 1,2 … +∞,对于每个空间虫洞,有两个值L和R,表示此虫洞只允许编号从L到 R的泡 泡怪通过,pppfish现在在1号中转站,他想带尽可能多的泡 泡怪到达N号中转站,于是 pppfish找到了机智的你,希望你告诉 他最多可以带多少个泡泡怪,同时他还想知道所 有泡泡怪的编号(若 有多组解取字典序最小的一组 )

Input

第一行两个用空格隔开的整数N,M(2<=N<=1000,0<=M<=3000) 接下来M行,每行四个用空格隔开的整数a,b,l,r 表示在a,b中转站间有一个空间虫洞允许编号l~r的泡泡怪通过。(1<=a, b<=N,1<=l<=r<=1e6

Output

第一行一个整数ans,表示最多能携带的泡泡怪数量 接下来一行ans个用空格隔开的正整数,表示泡泡怪的编号,从小到大依次输出,如 果没有泡泡怪能通过只要输出“0”就可以了

Sample Input

Input1:
4 4
1 2 1 10
2 4 3 5
1 3 1 5
2 4 2 7
Input2:
2 2
1 2 1 3
1 2 4 6

Sample Output

Output1:
6
2 3 4 5 6 7
Output2:
3
1 2 3

Data Constraint

30%的数据 1 <= N,M <= 10
100%的数据 2 <= N <= 1000, 0 <= M <= 3000, 1 <= a, b <= N, 1 <= l <= r <= 10^6

分析:
首先把区间左端点排序,依次插入区间,那么插入的区间的交集的左端点就是最后一次插入的区间左端点,右端点时 1 1 n路径上边权的最小值,维护一棵最大生成树即可。由于数据较小,可以使用非路径压缩的并查集,直接上LCT也可以,一个板子下去就好了。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>

const int maxn=5007;
const int maxe=10007;
const int inf=0x3f3f3f3f;

using namespace std;

int n,m,l,r,ans;
int val[maxn];
struct edge{
    int x,y,l,r;
}g[maxe];

struct node{
    int l,r,fa,data,id;
    int rev;
}t[maxn+maxe];

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

void updata(int x)
{
    int l=t[x].l,r=t[x].r;
    if (t[l].data<t[r].data) t[x].data=t[l].data,t[x].id=t[l].id;
                        else t[x].data=t[r].data,t[x].id=t[r].id;
    if (val[x]<t[x].data) t[x].data=val[x],t[x].id=x;
}

bool isroot(int x)
{
    return (x!=t[t[x].fa].l) && (x!=t[t[x].fa].r);
}

void remove(int x)
{
    if (!isroot(x)) remove(t[x].fa);
    if (t[x].rev)
    {
        t[x].rev^=1;
        swap(t[x].l,t[x].r);
        if (t[x].l) t[t[x].l].rev^=1;
        if (t[x].r) t[t[x].r].rev^=1;
    }
}

void rttr(int x)
{
    int y=t[x].l;
    t[x].l=t[y].r;
    if (t[y].r) t[t[y].r].fa=x;
    if (x==t[t[x].fa].l) t[t[x].fa].l=y;
    else if (x==t[t[x].fa].r) t[t[x].fa].r=y;
    t[y].fa=t[x].fa;
    t[x].fa=y;
    t[y].r=x;
    updata(x); updata(y);
}

void rttl(int x)
{
    int y=t[x].r;
    t[x].r=t[y].l;
    if (t[y].l) t[t[y].l].fa=x;
    if (x==t[t[x].fa].l) t[t[x].fa].l=y;
    else if (x==t[t[x].fa].r) t[t[x].fa].r=y;
    t[y].fa=t[x].fa;
    t[x].fa=y;
    t[y].l=x;
    updata(x); updata(y);
}

void splay(int x)
{
    remove(x);
    while (!isroot(x))
    {
        int p=t[x].fa,g=t[p].fa;
        if (isroot(p))
        {
            if (x==t[p].l) rttr(p);
                      else rttl(p);
        }
        else
        {
            if (x==t[p].l)
            {
                if (p==t[g].l) rttr(p),rttr(g);
                          else rttr(p),rttl(g);
            }
            else
            {
                if (p==t[g].l) rttl(p),rttr(g);
                          else rttl(p),rttl(g);
            }
        }
    }
}

void access(int x)
{
    int y=0;
    while (x)
    {
        splay(x);
        t[x].r=y;
        updata(x);
        y=x;x=t[x].fa;
    }
}

void makeroot(int x)
{
    access(x);
    splay(x);
    t[x].rev^=1;
}

int find(int x)
{
    if (isroot(x)) return x;
              else return find(t[x].fa);
}

void link(int x,int y)
{
    makeroot(x);
    access(y);
    splay(y);
    t[x].fa=y;
}

void cut(int x,int y)
{
    makeroot(x);
    access(y);
    splay(y);
    t[x].fa=0; t[y].l=0;
}

bool check(int x,int y)
{
    makeroot(x);
    access(y);
    splay(y);
    return find(x)==y; 
}

int main()
{
    freopen("travel.in","r",stdin);
    freopen("travel.out","w",stdout);
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;i++)
    {
        scanf("%d%d%d%d",&g[i].x,&g[i].y,&g[i].l,&g[i].r);
    }       
    sort(g+1,g+m+1,cmp);
    memset(val,inf,sizeof(val));
    int l=1,r=0;
    for (int i=0;i<=n+m;i++) t[i].data=inf;     
    for (int i=1;i<=m;i++)
    {
        if (g[i].x==g[i].y) continue;
        if (check(g[i].x,g[i].y) && (t[g[i].y].data<g[i].r))
        {
            int d=t[g[i].y].id;
            cut(g[d-n].x,d);
            cut(d,g[d-n].y);
        }
        if (!check(g[i].x,g[i].y))
        {
            val[i+n]=g[i].r;
            link(g[i].x,i+n);
            link(i+n,g[i].y);
        }
        if (check(1,n))
        {
            if (ans<(t[n].data-g[i].l+1))
            {
                ans=t[n].data-g[i].l+1;
                l=g[i].l;
                r=t[n].data;
            }
        }
    }
    printf("%d\n",ans);
    for (int i=l;i<=r;i++) printf("%d ",i);
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值