码迷,mamicode.com
首页 > 其他好文 > 详细

CF487E Tourists (圆方树,LCT)

时间:2020-03-28 13:25:21      阅读:59      评论:0      收藏:0      [点我收藏+]

标签:odi   模板   stdout   ring   namespace   back   main   方便   size   

圆方树模板题.    

建出圆方树.    

对于每个方点,只维护方点儿子的最小值,不维护方点父亲的值,这样的话每次修改只会改一个方点.   

我们需要支持单点修改,链查询,求 lca.   

LCT 可以非常方便地维护这些东西,然后如果 lca 是方点的话特判一下方点父亲的点值即可.   

code: 

#include <cstdio> 
#include <algorithm> 
#include <set>   
#include <vector>  
#include <cstring>  
 
#define setI(s) freopen(s".in","r",stdin) 
#define setO(s) freopen(s".out","w",stdout) 
#define setIO(s) setI(s),setO(s)  

using namespace std;   

const int N=2e5+5;      
const int inf=1e9+2;                     

namespace lct {  
    #define lson s[x].ch[0] 
    #define rson s[x].ch[1] 
    struct data 
    {
        int ch[2],rev,val,mi,f;         
        data(int x=inf) { ch[0]=ch[1]=0,val=mi=x; }       
    }s[N];   
    int sta[N];     
    int get(int x) { return s[s[x].f].ch[1]==x; } 
    int isr(int x) { return s[s[x].f].ch[0]!=x&&s[s[x].f].ch[1]!=x; }   

    void pushup(int x) 
    {  
        s[x].mi=min(s[x].val,min(s[lson].mi,s[rson].mi));
    }    
    void mark(int x) 
    {
        if(!x) return;   
        swap(lson,rson),s[x].rev^=1; 
    }    
    void pushdown(int x) 
    {
        if(s[x].rev) 
            mark(lson),mark(rson),s[x].rev=0;  
    }     
    void rotate(int x) 
    { 
        int old=s[x].f,fold=s[old].f,which=get(x);  
        if(!isr(old)) 
            s[fold].ch[s[fold].ch[1]==old]=x;     
        s[old].ch[which]=s[x].ch[which^1];   
        if(s[old].ch[which]) 
            s[s[old].ch[which]].f=old;   
        s[x].ch[which^1]=old,s[old].f=x,s[x].f=fold;   
        pushup(old),pushup(x); 
    }
    void splay(int x) 
    {
        int u=x,v=0,fa;   
        for(sta[++v]=u;!isr(u);u=s[u].f)   
            sta[++v]=s[u].f;   
        for(;v;--v) 
            pushdown(sta[v]);   
        for(u=s[u].f;(fa=s[x].f)!=u;rotate(x))       
            if(s[fa].f!=u)   
                rotate(get(fa)==get(x)?fa:x);     
    }
    int Access(int x) 
    {  
        int y=0; 
        for(;x;y=x,x=s[x].f)   
            splay(x),rson=y,pushup(x);     
        return y; 
    }
    void makert(int x) 
    {
        Access(x),splay(x),mark(x);  
    }
    void split(int x,int y) 
    {
        makert(x),Access(y),splay(y);  
    }    
    void link(int x,int y) 
    { 
        s[x].f=y;     
    }  
    int get_lca(int x,int y) 
    {    
        Access(x);      
        return Access(y); 
    }    
};    
 
vector<int>G[N];  
int val[N],dfn[N],low[N],S[N],tim,top,tot;         
int hd[N],to[N],nex[N],edges,n,m,Q;  
int fa[N];         
multiset<int>mi[N];     
void add(int u,int v) 
{
    nex[++edges]=hd[u],hd[u]=edges,to[edges]=v;   
}     
void tarjan(int u) 
{
    dfn[u]=low[u]=++tim; 
    S[++top]=u;    
    for(int i=hd[u];i;i=nex[i]) 
    {
        int v=to[i];    
        if(!dfn[v]) 
        {
            tarjan(v),low[u]=min(low[u],low[v]);            
            if(low[v]>=dfn[u]) 
            {       
                ++tot;   
                G[tot].push_back(u);    
                G[u].push_back(tot);  
                for(int x=0;x!=v;--top) 
                {
                    x=S[top];      
                    G[tot].push_back(x); 
                    G[x].push_back(tot);      
                }
            }
        }
        else low[u]=min(low[u],dfn[v]);       
    }
}              
void dfs(int x,int ff) 
{     
    if(ff) 
        lct::link(x,ff); 
    if(x<=n) 
    {    
        if(ff) mi[ff].insert(val[x]);      
        lct::s[x].val=lct::s[x].mi=val[x];    
    }
    for(int i=0;i<G[x].size();++i) 
    {
        int y=G[x][i];   
        if(y!=ff) fa[y]=x,dfs(y,x);    
    }      
    if(x>n)  
    {
        lct::s[x].val=lct::s[x].mi=*mi[x].begin();  
    }
}
int main() 
{   
    //setI("input");                    
    scanf("%d%d%d",&n,&m,&Q);    
    for(int i=1;i<=n;++i)   
        scanf("%d",&val[i]);     
    for(int i=1;i<=m;++i) 
    {
        int x,y; 
        scanf("%d%d",&x,&y); 
        add(x,y),add(y,x);    
    }     
    tot=n;  
    for(int i=1;i<=n;++i)  
        if(!dfn[i])  
            tarjan(i);      
    dfs(1,0);      
    val[0]=inf;     
    for(int i=1;i<=Q;++i) 
    {     
        char ch[2];   
        int x,b;  
        scanf("%s%d%d",ch,&x,&b);   
        if(ch[0]==‘C‘)  
        {  
            lct::splay(x); 
            lct::s[x].val=b;   
            lct::pushup(x);           

            if(fa[x]) 
            {
                mi[fa[x]].erase(mi[fa[x]].lower_bound(val[x]));    
                mi[fa[x]].insert(b);    
                lct::splay(fa[x]);    
                lct::s[fa[x]].val=*mi[fa[x]].begin();         
                lct::pushup(fa[x]);   
            }              

            val[x]=b;    
            // modify(val[x] -> b)  
        } 
        else 
        {
            // query(a,b)      
            int lca=lct::get_lca(x,b);               
            if(lca<=n)  lca=0;   
            lct::split(x,b);     
            printf("%d\n",min(lct::s[b].mi,val[fa[lca]]));  
            lct::makert(1);         
        }     
    }                 
    return 0;  
}

  

CF487E Tourists (圆方树,LCT)

标签:odi   模板   stdout   ring   namespace   back   main   方便   size   

原文地址:https://www.cnblogs.com/guangheli/p/12586841.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!