CF487E Tourists

CF487E Tourists

圆方树

本题中,很容易考虑到建成圆方树,把所有点双内的节点最小值作为方点的权值,然后求链上最小值即可。

这样做的正确性显然,但是难以维护修改操作。

我们每次修改一个节点,都需要修改其相邻的方点,这样的复杂度是无法接受的。

我们考虑换一个方式,我们钦定一个叶子节点为圆方树的根后,对于方点,我们只记录其儿子节点的\(\min\),那么修改只需要修改父亲方点。

而求链最小值时,我们发现,除了两个节点的\(lca\)为方点的情况,我们求出的链最小值仍然是对的。那么我们只需要判断一下是否是方点,如果是,把其父亲统计入答案即可。

\(lca\)和链信息维护,一个\(LCT\)就完事。

对于方点的维护,可以用\(multiset\)或可删堆。

\(Code:\)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<stack>
#include<queue>
#define N 100005
#define M 200005
using namespace std;
const int INF=1000000007;
stack<int>s;
char opt[5];
int n,m,Q,x,y,ct,rt=1,w[M];
int o[N];
struct edge
{
    int nxt,v;
    edge (int Nxt=0,int V=0)
    {
        nxt=Nxt,v=V;
    }
}e[N << 1];
int F[M];
#define ls(x) a[x].ch[0]
#define rs(x) a[x].ch[1]
#define fa(x) a[x].f
#define val(x) a[x].value
#define rev(x) a[x].tag
struct DelHeap
{
    priority_queue<int,vector<int>,greater<int> >q1,q2;
    int top()
    {
        while (!q2.empty() && q1.top()==q2.top())
            q1.pop(),q2.pop();
        return q1.top();
    }
    void pop()
    {
        while (!q2.empty() && q1.top()==q2.top())
            q1.pop(),q2.pop();
        q1.pop();
    }
    void push(int x)
    {
        q1.push(x);
    }
    void erase(int x)
    {
        q2.push(x);
    }
}g[M];
struct Link_Cut_Tree
{
    int ch[2],f,value;
    bool tag;
}a[M];
int q[M];
int id(int x)
{
    return ls(fa(x))==x?0:1;
}
bool isrt(int x)
{
    return ls(fa(x))!=x && rs(fa(x))!=x;
}
void connect(int x,int F,int son)
{
    fa(x)=F;
    a[F].ch[son]=x;
}
void update(int x)
{
    val(x)=min(w[x],min(val(ls(x)),val(rs(x))));
}
void rot(int x)
{
    int y=fa(x),r=fa(y);
    int yson=id(x),rson=id(y);
    if (isrt(y))
        fa(x)=r; else
        connect(x,r,rson);
    connect(a[x].ch[yson^1],y,yson);
    connect(y,x,yson^1);
    update(y),update(x);
}
void push_rev(int x)
{
    if (!x)
        return;
    swap(ls(x),rs(x));
    rev(x)=!rev(x);
}
void push_down(int x)
{
    if (rev(x))
    {
        push_rev(ls(x));
        push_rev(rs(x));
        rev(x)=0;
    }
}
void splay(int x)
{
    int g=x,k=0;
    q[++k]=x;
    while (!isrt(g))
        g=fa(g),q[++k]=g;
    while (k)
        push_down(q[k--]);
    while (!isrt(x))
    {
        int y=fa(x);
        if (isrt(y))
            rot(x); else
        if (id(x)==id(y))
            rot(y),rot(x); else
            rot(x),rot(x);
    }
}
void access(int x)
{
    for (int y=0;x;y=x,x=fa(x))
    {
        splay(x);
        rs(x)=y;
        update(x);
    }
}
void makeroot(int x)
{
    access(x);
    splay(x);
    push_rev(x);
}
void split(int x,int y)
{
    makeroot(x);
    access(y);
    splay(y);
}
void link(int x,int y)
{
    makeroot(x);
    fa(x)=y;
}
int lca(int x,int y)
{
    makeroot(rt);
    access(y);
    int t=0;
    for (;x;t=x,x=fa(x))
    {
        splay(x);
        rs(x)=t;
        update(x);
    }
    return t;
}
int tot,fr[N];
int cnt=0,dfn[N],low[N];
void add(int x,int y)
{
    ++tot;
    e[tot]=edge(fr[x],y),fr[x]=tot;
}
void add_edge(int x,int y)
{
    add(x,y),add(y,x);
}
void Tarjan(int u)
{
    dfn[u]=low[u]=++cnt;
    s.push(u);
    for (int i=fr[u];i;i=e[i].nxt)
    {
        int v=e[i].v;
        if (!dfn[v])
        {
            Tarjan(v);
            if (low[v]==dfn[u])
            {
                ++ct;
                F[ct]=u;
                o[0]=0;
                int t;
                do
                {
                    t=s.top();
                    s.pop();
                    g[ct].push(w[t]);
                    o[++o[0]]=t;
                    F[t]=ct;
                } while (t!=v);
                o[++o[0]]=u;
                w[ct]=g[ct].top();
                val(ct)=w[ct];
                for (int j=1;j<=o[0];++j)
                    link(ct,o[j]);
            }
            low[u]=min(low[u],low[v]);
        } else
            low[u]=min(low[u],dfn[v]);
    }
}
int main()
{
    val(0)=INF;
    scanf("%d%d%d",&n,&m,&Q),ct=n;
    for (int i=1;i<=n;++i)
        scanf("%d",&w[i]),val(i)=w[i];
    for (int i=1;i<=m;++i)
    {
        scanf("%d%d",&x,&y);
        add_edge(x,y);
    }
    Tarjan(1);
    while (Q--)
    {
        scanf("%s%d%d",opt,&x,&y);
        if (opt[0]=='C')
        {
            int s=F[x];
            if (s)
            {
                g[s].erase(w[x]);
                g[s].push(y);
                splay(s);
                w[s]=g[s].top();
                update(s);
            }
            splay(x);
            w[x]=y;
            update(x);
        } else
        {
            split(x,y);
            int ans=val(y);
            int s=lca(x,y);
            if (s>n)
                ans=min(ans,w[F[s]]);
            printf("%d\n",ans);
        }
    }
    return 0;
}
posted @ 2020-11-04 10:58  GK0328  阅读(45)  评论(0编辑  收藏  举报