1. 程式人生 > >BZOJ4129 樹上莫隊+權值分塊

BZOJ4129 樹上莫隊+權值分塊

這道題來來回回搞了近十個小時

完全暴露出了自己樹上操作的薄弱

放在區間上面秒殺的題目 放到樹上不知所措

先是離散化寫了三個多小時 一直wa 後來發現離散化的話就不能用分塊做 要用其他資料結構

然後又研究其他資料結構 比如樹狀陣列 還寫炸了 至今不知道炸在哪裡

於是只能回頭搞分塊 終於是調了出來

這題因為是查詢樹上的一條鏈 所以權值大於n的點可以直接丟掉 因為根本達不到那個點

這樣一來問題就簡單很多 也因此不用離散化了

至於其他就是樹上帶修莫隊的基本操作

聽說樹上莫隊還能用尤拉序寫 此處挖坑以後再填

程式碼如下

#include<bits/stdc++.h>
using namespace std;
const int maxn=5e4+5;
struct Edge
{
    int y,next;
}edge[2*maxn];
int cnt,cntq,cntc,all,n,m,top,unit,tb;
int head[maxn],Be[maxn],st[maxn],fa[maxn][20],deep[maxn],a[maxn],now[maxn],ans[maxn],dfn[maxn];
int num[maxn],siz[maxn],block[maxn];
bool vis[maxn];
struct node
{
    int u,v,t,id;
    bool operator <(const node &a)const
    {
        return Be[u]==Be[a.u]?(Be[v]==Be[a.v]?t<a.t:dfn[v]<dfn[a.v]):Be[u]<Be[a.u];
    }
}q[maxn];
struct change
{
    int u,New,old;
}c[maxn];
void addedge(int x,int y)
{
    edge[++cnt].y=y;
    edge[cnt].next=head[x];
    head[x]=cnt;
}
void dfs(int x)
{
    dfn[x]=++dfn[0];
    for(int i=head[x];i;i=edge[i].next)
    {
        int v=edge[i].y;
        if(v!=fa[x][0])
        {
            fa[v][0]=x;
            deep[v]=deep[x]+1;
            dfs(v);
        }
    }
}
int LCA(int x,int y)
{
    if(deep[x]<deep[y])
        swap(x,y);
    for(int i=15;i>=0;i--)
    {
        if(fa[x][i]&&deep[fa[x][i]]>=deep[y])
            x=fa[x][i];
    }
    if(x==y) return x;
    for(int i=15;i>=0;i--)
    {
        if(fa[x][i]&&fa[x][i]!=fa[y][i])
            x=fa[x][i],y=fa[y][i];
    }
    return fa[x][0];
}
void work(int x)
{
    if(a[x]>n)
    {
        vis[x]^=1;
        return ;
    }
    if(vis[x])
    {
        siz[block[a[x]]]+=(--num[a[x]]==0);
    }
    else
    {
        siz[block[a[x]]]-=(++num[a[x]]==1);
    }
    vis[x]^=1;
}
void move(int x,int y)
{
    if(deep[x]<deep[y])
        swap(x,y);
    while(deep[x]>deep[y])
    {
        work(x);
        x=fa[x][0];
    }
    while(x!=y)
    {
        work(x);
        work(y);
        x=fa[x][0];
        y=fa[y][0];
    }
}
int find()
{
    int p=tb+1;
    for(int i=0;i<=tb;i++)
        if(siz[i])
        {
            p=i;
            break;
        }
    for(int i=p*tb;i<(p+1)*tb;i++)
    {
        if(!num[i])
            return i;
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    unit=pow(n,2.0/3);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        now[i]=a[i];
    }
    for(int i=2;i<=n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        addedge(x,y);
        addedge(y,x);
    }
    dfs(1);
    for(int i=1;i<=n;i++)
        Be[i]=(dfn[i]+1)/unit;
    for(int i=1;i<=15;i++)
        for(int j=1;j<=n;j++)
            fa[j][i]=fa[fa[j][i-1]][i-1];
    tb=sqrt(n+1);
    for(int i=0;i<=n;i++)
    {
        block[i]=i/tb;
        siz[block[i]]++;
    }
    for(int i=1;i<=m;i++)
    {
        int op,x,y;
        scanf("%d%d%d",&op,&x,&y);
        if(op==0)
        {
            c[++cntc]=(change){x,y,now[x]};
            now[x]=y;
        }
        else
        {
            q[++cntq]=(node){x,y,cntc,cntq};
        }
    }
    sort(q+1,q+cntq+1);
    int T=0,u=1,v=1;
    for(int i=1;i<=cntq;i++)
    {
        while(T<q[i].t)
        {
            T++;
            if(vis[c[T].u])
            {
                work(c[T].u);
                a[c[T].u]=c[T].New;
                work(c[T].u);
            }
            else a[c[T].u]=c[T].New;
        }
        while(T>q[i].t)
        {
            if(vis[c[T].u])
            {
                work(c[T].u);
                a[c[T].u]=c[T].old;
                work(c[T].u);
            }
            else a[c[T].u]=c[T].old;
            T--;
        }
        if(u!=q[i].u)
        {
            move(u,q[i].u),u=q[i].u;
        }
        if(v!=q[i].v)
        {
            move(v,q[i].v),v=q[i].v;
        }
        int tp=LCA(u,v);
        work(tp);
        ans[q[i].id]=find();
        work(tp);
    }
    for(int i=1;i<=cntq;i++)
        printf("%d\n",ans[i]);
    return 0;
}