1. 程式人生 > >SPOJ2939 QTREE5(LCT維護子樹資訊)

SPOJ2939 QTREE5(LCT維護子樹資訊)

QWQ嚶嚶嚶
此題正規題解應該是邊分治??或者是樹剖(總之不是LCT)

但是我這裡還是把它當成一個LCT題目來做

首先,這個題的重點還是在update上

因為有\(makeroot\)這個操作的存在,所以自然避免不了\(reverse\),而當\(reverse\)之後,會影響到每個點維護的值的時候,就需要同時維護兩個相反的陣列,在\(reverse\)的時候,直接\(swap\)

對於本題來說,我們對於一個點需要維護一個虛子樹的\(maxdis\) (這裡需要\(multiset\)來維護,因為access的時候,涉及到修改的問題)
一個到深度最淺的點的\(ans1\),到深度最深的點的\(ans2\)

,還有一個子\(splay\)的權值和

考慮轉移,ans1的轉移顯然可以由\(ans1[ch[x][0]]\)轉移而來(表示左子樹內部的路徑),其次,他還可以從\(min(fir(s[x]),ans1[ch[x][1]])+val[x]+val[ch[x][0]\)轉移而來(表示從右子樹或者虛子樹開始的一條路徑),如果當前點是合法的顏色,那麼還可以從當前點開始的一條路徑更新\(ans1\),而\(ans2\)直接全部反過來就好

void update(int x)
{
    if (!x) return;
    sval[x]=sval[ch[x][0]]+sval[ch[x][1]]+val[x];
    ans1[x]=min(ans1[ch[x][0]],min(fir(x),ans1[ch[x][1]])+val[x]+sval[ch[x][0]]);
    ans2[x]=min(ans2[ch[x][1]],min(fir(x),ans2[ch[x][0]])+val[x]+sval[ch[x][1]]);
    //cout<<x<<" "<<ans1[x]<<" "<<ans2[x]<<" "<<sval[x]<<endl;
    if (col[x])
    {
        ans1[x]=min(ans1[x],sval[ch[x][0]]);
        ans2[x]=min(ans2[x],sval[ch[x][1]]);
    }
    //lmn[x]=min(lmn[ls],len[ls]+val[x]+min(w[x],fir(s[x]),lmn[rs]));
    //rmn[x]=min(rmn[rs],len[rs]+min(w[x],fir(s[x]),rmn[ls]+val[x]));
}

其他的話,就是一些小細節了,可以直接看程式碼

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
#include<map>
#include<set>

using namespace std;

inline int read()
{
  int x=0,f=1;char ch=getchar();
  while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
  while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
  return x*f;
}

const int maxn = 5e5+1e2;
//const int inf = 1e9;

int lubenwei;
int ch[maxn][3];
int inf;
int fa[maxn],rev[maxn],ans1[maxn],ans2[maxn];
int sval[maxn],val[maxn];
int col[maxn];
int n,m;
multiset<int> s[maxn];
int tot;
int st[maxn];

int son(int x)
{
    if (ch[fa[x]][0]==x) return 0;
    else return 1;
}

bool notroot(int x)
{
    return ch[fa[x]][0]==x || ch[fa[x]][1]==x;
}

void reverse(int x)
{
    swap(ans1[x],ans2[x]);
    rev[x]^=1;
    swap(ch[x][0],ch[x][1]);
}

int fir(int x)
{
    //cout<<"ymh"<<endl;
   if (s[x].size()>=1) return *(s[x].begin());
   else return inf;
}

void update(int x)
{
    if (!x) return;
    sval[x]=sval[ch[x][0]]+sval[ch[x][1]]+val[x];
    ans1[x]=min(ans1[ch[x][0]],min(fir(x),ans1[ch[x][1]])+val[x]+sval[ch[x][0]]);
    ans2[x]=min(ans2[ch[x][1]],min(fir(x),ans2[ch[x][0]])+val[x]+sval[ch[x][1]]);
    //cout<<x<<" "<<ans1[x]<<" "<<ans2[x]<<" "<<sval[x]<<endl;
    if (col[x])
    {
        ans1[x]=min(ans1[x],sval[ch[x][0]]);
        ans2[x]=min(ans2[x],sval[ch[x][1]]);
    }
    //lmn[x]=min(lmn[ls],len[ls]+val[x]+min(w[x],fir(s[x]),lmn[rs]));
    //rmn[x]=min(rmn[rs],len[rs]+min(w[x],fir(s[x]),rmn[ls]+val[x]));
}

void pushdown(int x)
{
    if (rev[x])
    {
        if (ch[x][0]) reverse(ch[x][0]);
        if (ch[x][1]) reverse(ch[x][1]);
        rev[x]=0;
    }
}

void rotate(int x)
{
    int y=fa[x],z=fa[y];
    int b=son(x),c=son(y);
    if (notroot(y)) ch[z][c]=x;
    fa[x]=z;
    ch[y][b]=ch[x][!b];
    fa[ch[x][!b]]=y;
    ch[x][!b]=y;
    fa[y]=x;
    update(y);
    update(x);
}

void splay(int x)
{
    int y=x,cnt=0;
    st[++cnt]=y;
    while (notroot(y)) y=fa[y],st[++cnt]=y;
    while (cnt) pushdown(st[cnt--]);

    while (notroot(x))
    {
        int y=fa[x],z=fa[y];
        int b=son(x),c=son(y);
        if (notroot(y))
        {
            if (b==c) rotate(y);
            else rotate(x);
        }
        rotate(x);
        
    }
    ///cout<<2<<endl;
    update(x);
}

void access(int x)
{
    for (int y=0;x;y=x,x=fa[x])
    {
        splay(x);
    //  cout<<1;
        if (ch[x][1])s[x].insert(ans1[ch[x][1]]);
        if (y && s[x].find(ans1[y])!=s[x].end()) s[x].erase(s[x].find(ans1[y]));
        ch[x][1]=y;
        update(x);
    }
//  cout<<"wancheng";
}

void makeroot(int x)
{
    access(x);//cout<<x<<endl;
    splay(x);
    reverse(x);
}

int findroot(int x)
{
    access(x);
    splay(x);
    while (ch[x][0])
    {
        pushdown(x);
        x=ch[x][0];
    }
    return x;
}

void split(int x,int y)
{
    makeroot(x);
    access(y);
    splay(y);
}

void link(int x,int y)
{
    split(x,y);
    if (findroot(y)!=x)
    {
        fa[x]=y;
        s[y].insert(ans1[x]);
        update(y);
    }
}
int main()
{
    memset(ans1,127/3,sizeof(ans1));
    memset(ans2,127/3,sizeof(ans2));
   inf = ans1[maxn-3];  
   n=read();
   lubenwei=0;
   tot=n;
   for (int i=1;i<n;i++)
   {
     int x=read(),y=read();
     val[++tot]=1;
     link(x,tot);
     link(y,tot);
   }
   m=read();
   makeroot(1);
   for (int i=1;i<=m;i++)
   {
      int opt=read();
      int x=read();
      if (opt==0)
      {
        makeroot(x);
        col[x]^=1;
        if (col[x]==1) lubenwei++;
        else lubenwei--;
        update(x);
      }
      if (opt==1)
      {
         makeroot(x);
         if (!lubenwei) cout<<-1<<"\n";
         else
         if (col[x]) cout<<0<<"\n";
         else cout<<ans1[x]<<"\n";
      }
     // cout<<"6deyanse:"<<col[x]<<endl;
   }
   return 0;
}