1. 程式人生 > >【SDOI2017】樹點染色【線段樹+LCT】

【SDOI2017】樹點染色【線段樹+LCT】

get d+ i++ read 改變 rotate def 維護 n)

本來只是想練練LCT,沒想到是個線段樹

對於操作1:誒新的顏色?這不是access嗎?

也就是說,我們用一棵splay來表示一種顏色

操作2直接在LCT上亂搞……

不對啊,操作3要查子樹

誒好像是靜態的

那可以考慮線段樹維護dfs序

現在要考慮怎麽維護權值

我們發現開始的時候權值就是節點的深度

而在且只在access的時候會改變權值

試試魔改access?

原來:

for (int y=0;x;y=x,x=fa[x])
{
    splay(x);
    ch[x][1]=y;
    update(x);
}

那麽主要就是\(ch[x][1]=y\)

實際上這句話包含兩個操作:清除\(ch[x][1]\)

,把\(y\)接到\(x\)的右兒子

清除\(ch[x][1]\),相當於把原來的重邊斷開

我們只考慮當前這個點改了之後的影響

註意既然他們是重邊連起來的,他們原來一定是同色的

而改了之後他們就不同了,所以y的子樹權值都會增加1

並且他也不會和這條到根路徑上任何一個出現過的顏色相同

同樣,把\(y\)接到\(x\)的右兒子,意味著x和y同色了,而原來是不同的,所以y的子樹權值都會減少1

線段樹維護一下就好

操作2直接單點查詢,類似樹上前綴和就可以了

於是乎,LCT40多行……

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#define MAXN 1000005
#define MAXM 2000005
using namespace std;
inline int read()
{
    int ans=0;
    char c=getchar();
    while (!isdigit(c)) c=getchar();
    while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    return ans;
}
struct edge
{
    int u,v;
}e[MAXM];
int head[MAXN],nxt[MAXM],cnt;
void addnode(int u,int v)
{
    e[++cnt]=(edge){u,v};
    nxt[cnt]=head[u];
    head[u]=cnt;
}
int dep[MAXN],fa[MAXN],up[MAXN][20];
int dfn[MAXN],pos[MAXN],tim,end[MAXN];
void dfs(int u)
{
    dfn[u]=++tim;
    pos[tim]=u;
    for (int i=1;i<20;i++)
        up[u][i]=up[up[u][i-1]][i-1];
    for (int i=head[u];i;i=nxt[i])
        if (!dep[e[i].v])
        {
            dep[e[i].v]=dep[u]+1;
            up[e[i].v][0]=u;
            fa[e[i].v]=u;
            dfs(e[i].v);
        }
    end[u]=tim;
}
int lca(int x,int y)
{
    if (dep[x]<dep[y]) swap(x,y);
    int t=dep[x]-dep[y];
    for (int i=0;(1<<i)<=t;i++)
        if (t&(1<<i))
            x=up[x][i];
    if (x==y) return x;
    for (int i=19;i>=0;i--)
        if (up[x][i]!=up[y][i])
            x=up[x][i],y=up[y][i];
    return up[x][0];
}
namespace SGT
{
    #define lc p<<1
    #define rc p<<1|1
    struct SegmentTree
    {
        int l,r;
        int lazy;
        int mx;
    }t[MAXN<<2];
    void pushup(int p){t[p].mx=max(t[lc].mx,t[rc].mx);} 
    void pushlazy(int p,int v){t[p].mx+=v,t[p].lazy+=v;}
    void pushdown(int p) 
    {
        if (t[p].lazy)
        {
            pushlazy(lc,t[p].lazy);
            pushlazy(rc,t[p].lazy);
            t[p].lazy=0;
        }
    }
    void build(int p,int l,int r)
    {
        t[p].l=l,t[p].r=r;
        if (l==r){t[p].mx=dep[pos[l]];return;}
        int mid=(l+r)>>1;
        build(lc,l,mid),build(rc,mid+1,r);
        pushup(p);
    }
    void modify(int p,int l,int r,int v)
    {
        if (l<=t[p].l&&t[p].r<=r) return pushlazy(p,v);
        if (r<t[p].l||t[p].r<l) return;
        pushdown(p);
        if (l<=t[lc].r) modify(lc,l,r,v);
        if (t[rc].l<=r) modify(rc,l,r,v);
        pushup(p);
    }
    int querymax(int p,int l,int r)
    {
        pushdown(p);
        if (l<=t[p].l&&t[p].r<=r) return t[p].mx;
        if (r<t[p].l||t[p].r<l) return 0;
        int ans=0;
        if (l<=t[lc].r) ans=max(ans,querymax(lc,l,r));
        if (t[rc].l<=r) ans=max(ans,querymax(rc,l,r));
        return ans;
    }
    int query(int p,int k)
    {
        pushdown(p);
        if (t[p].l==t[p].r) return t[p].mx;
        if (k<=t[lc].r) return query(lc,k);
        else return query(rc,k);
    }
}
using namespace SGT;
namespace Splay
{
    int ch[MAXN][2];
    bool isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
    int get(int x){return ch[fa[x]][1]==x;}
    void rotate(int x)
    {
        int y=fa[x],z=fa[y];
        int l=get(x),r=l^1;
        int w=ch[x][r];
        if (!isroot(y)) ch[z][get(y)]=x;
        ch[x][r]=y,ch[y][l]=w;
        if (w) fa[w]=y;
        fa[y]=x,fa[x]=z;
    }
    void splay(int x)
    {
        while (!isroot(x))
        {
            int y=fa[x];
            if (!isroot(y))
            {
                if (get(x)==get(y)) rotate(y);
                else rotate(x);
            }
            rotate(x);
        }
    }
}
using namespace Splay;
namespace LCT
{
    int findroot(int x){while (ch[x][0]) x=ch[x][0];return x;}
    void access(int x)
    {
        int w;
        for (int y=0;x;y=x,x=fa[x])
        {
            splay(x);
            if (ch[x][1]){w=findroot(ch[x][1]),modify(1,dfn[w],end[w],1);}
            if (ch[x][1]=y){w=findroot(y),modify(1,dfn[w],end[w],-1);}
        }
    }
}
using namespace LCT;
int main()
{
    int n,m;
    n=read(),m=read();
    for (int i=1;i<n;i++)
    {
        int u,v;
        u=read(),v=read();
        addnode(u,v),addnode(v,u);
    }
    dep[1]=1;
    dfs(1);
    build(1,1,n);
    while (m--)
    {
        int op,x,y,l;
        op=read(),x=read();
        int ans;
        switch(op)
        {
            case 1:access(x);break;
            case 2:
                y=read();
                l=lca(x,y);
                ans=query(1,dfn[x]);
                ans+=query(1,dfn[y]);
                ans-=(query(1,dfn[l])<<1);
                printf("%d\n",ans+1);
                break;
            case 3:
                printf("%d\n",querymax(1,dfn[x],end[x]));
        }
    }
    return 0;
}

【SDOI2017】樹點染色【線段樹+LCT】