BZOJ 2594 LCT维护最小生成树

        调了好久啊,果然不是这错一点就是那错一点……

        我们可以把题目倒过来做,时间倒流,删边变成加边,对于每个查询(u,v),抓出来一条链记录最大值即可

        对于每个加入(u,v),先是找到u,v边上的最大值,如果当前u,v<_max,那么删去最大值那条边,加入u,v

        代码写得很丑,BZOJ上过不了,反正自己测过了~

#include <cstdio>
#include <stack>
#include <algorithm>
 
using namespace std;
 
const int INF = 1000001;
const int MAXN = 100001;
const int MAXM = 1000001;
const int MAXQ = 100001;
 
void READ(int &x)
{
    char c;
    x = 0;
    do c = getchar();while (c > '9' || c < '0');
    do x = x*10+c-48, c = getchar();while (c >= '0' && c <= '9');
}
 
struct Ques
{
    int oper,u,v,dist,id;
};
 
int n,m,q;
int f[2*MAXN];
Ques Q[MAXQ];
int ans[MAXQ];
 
struct Edge
{
    bool flag;
    int u,v,dist,id;
    bool operator < (const Edge &rhs) const
    {
        return u < rhs.u || (u == rhs.u && v < rhs.v);
    }
    Edge(int _u,int _v,int _dist,int _id):u(_u),v(_v),dist(_dist),id(_id){}
    Edge(){}
};
 
bool cmp1(Edge A,Edge B)
{
    return A.dist < B.dist;
}
 
bool cmp2(Edge A,Edge B)
{
    return A.id < B.id;
}
 
Edge Edges[2*MAXM];
 
struct Node *null;
struct Node 
{
    int flag;
    int id;
    int dist,size;
    int _max,maxlocal;
    Node *ch[2],*f;
    int d(){return f->ch[1] == this ? 1 : 0;}
    bool check(){return f != null && (f->ch[0] == this || f->ch[1] == this);}
    void setc(Node *c,int d){ch[d] = c, c->f = this;}
    Node(int _dist):dist(_dist){size = 1, f = ch[0] = ch[1] = null, flag = false;}
    Node(){size = 0, dist = _max = -INF, f = ch[0] = ch[1] = NULL, flag = false;}
    void maintain()
    {
        size = 1+ch[0]->size+ch[1]->size;
        maxlocal = id, 
        _max = dist;
        if (ch[0]->_max > _max) maxlocal = ch[0]->maxlocal,_max = ch[0]->_max;
        if (ch[1]->_max > _max) maxlocal = ch[1]->maxlocal,_max = ch[1]->_max;
    }
    void pushdown()
    {
        if (flag)
        {
            flag = false;
            ch[0]->flag ^= 1, ch[1]->flag ^= 1;
            swap(ch[0],ch[1]);
        }
    }
};
 
Node *p[MAXM*2];
 
void rotate(Node *p)
{
    Node *x = p->f;
    x->pushdown();p->pushdown();
    int d = p->d();
    if (!x->check()) p->f = x->f;
    else x->f->setc(p,x->d());
    x->setc(p->ch[d^1],d);
    p->setc(x,d^1);
    x->maintain();
}
 
void Splay(Node *p)
{
    p->pushdown();
    while (p->check())
    {
        Node *x = p->f;
        if (!x->check()) rotate(p);
        else x->d() == p->d() ? (rotate(x),rotate(p)) : (rotate(p),rotate(p));
    }
    p->maintain();
}
 
void Access(Node *p)
{
    for (Node *q = null; p != null; p = p->f)
    {
        Splay(p);
        p->setc(q,1);
        (q = p)->maintain();
    }
}
 
void MakeRoot(Node *p)
{
    Access(p);Splay(p);
    p->flag ^= 1;
}
 
void Link(Node *p,Node *q)
{
    MakeRoot(p);
    p->f = q;
}
 
void Cut(Node *p,Node *q)
{
    MakeRoot(p);
    Access(q);Splay(q);
    q->ch[0] = p->f = null;
    q->maintain();
}
 
Node* Query(Node *p,Node *q)
{
    MakeRoot(p);
    Access(q);Splay(q);
    return q;
}
 
int find(int x)
{
    return x == f[x] ? f[x] : f[x] = find(f[x]);
}
 
int main()
{
    null = new Node();
    READ(n);READ(m);READ(q);
    for (int i=1;i<=2*m;i++) p[i] = new Node(0), p[i]->id = i;
    for (int i=1;i<=m;i++) 
    {
        READ(Edges[i].u),READ(Edges[i].v),READ(Edges[i].dist);
        if (Edges[i].u > Edges[i].v) swap(Edges[i].u,Edges[i].v);
    }
    sort(Edges+1,Edges+m+1,cmp1);
    for (int i=1;i<=m;i++) Edges[i].id = i;
    sort(Edges+1,Edges+m+1);
    for (int i=1;i<=q;i++)
    {
        READ(Q[i].oper),READ(Q[i].u),READ(Q[i].v);
        if (Q[i].u > Q[i].v) swap(Q[i].u,Q[i].v);
        if (Q[i].oper == 1) continue;
        int temp = lower_bound(Edges+1,Edges+m+1,(Edge){Q[i].u,Q[i].v,0,0})-Edges;
        Edges[temp].flag = true;
        Q[i].dist = Edges[temp].dist;
        Q[i].id = Edges[temp].id;
    }
    sort(Edges+1,Edges+m+1,cmp2);
    for (int i=1;i<=2*m;i++) f[i] = i;
    int cnt = 0;
    for (int i=1;i<=m;i++) if (!Edges[i].flag)
    {
        int Su = find(Edges[i].u);
        int Sv = find(Edges[i].v);
        if (Su == Sv) continue;
        f[Su] = Sv;
        p[i+n]->dist = Edges[i].dist;
        Link(p[Edges[i].u],p[i+n]);Link(p[Edges[i].v],p[i+n]);
        cnt++;
        if (cnt == n-1) break;
    }
    for (int i=q;i>0;i--)
    {
        if (Q[i].oper == 1) ans[i] = Query(p[Q[i].u],p[Q[i].v])->_max;
        else
        {
            Node *temp = Query(p[Q[i].u],p[Q[i].v]);
            if (Q[i].dist < temp->_max)
            {
                int point = temp->maxlocal-n;
                Cut(p[point+n],p[Edges[point].u]);Cut(p[point+n],p[Edges[point].v]);
                point = Q[i].id;
                p[point+n]->dist = Q[i].dist;
                Link(p[point+n],p[Edges[point].u]);Link(p[point+n],p[Edges[point].v]);
            }
        }
    }
    for (int i=1;i<=q;i++) if (Q[i].oper == 1) printf("%d\n",ans[i]);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值