【WC2014】紫荊花之戀

【WC2014】紫荊花之戀

第二道點分題就切紫荊花之戀真的好嗎…

題意: 在一棵樹上不斷加入一個節點[共n105 ],同時給出{a[在樹上的父親], c[與父親的距離], r[“感受值”]},並詢問此時共多少對節點滿足dist(i,j)ri+rj ,強制在線。

思路正如政治老師所說
1. 如果只要求求解一次,顯然點分治可以求解,只需要作如下的分析:

令r爲當前根,則
dist(i,j)ri+rjdist(i,r)rirjdist(j,r)
所以可以用一個數據結構維護當前根的所有dist(i,r)ri ,以及當前子樹對於上一層根的dist(i,r)ri ,對於每一個rjdist(j,r) 查詢兩次並求差[跨根的路徑兩端不在同一子樹]即可。

2. 如果不需要強制在線,只需要將點分樹動態化,每添加一個節點時將其在點分樹的祖先遍歷一遍即可。
3. 如果需要強制在線,那麼實時維護點分樹是不現實的。此時可以借鑑替罪羊樹的思想,當一個點分子樹的平衡度(自行百度“替罪羊樹”)超過α 時暴力重建子樹,複雜度有均攤保證。

所以,最後我們得到了一個通過 動態點分治+樹堆+倍增[LCA]+替罪羊樹 實現的時間複雜度均攤 Θ(nlog2n) 的優秀算法。

P.S. 這道題我一開始在uoj 上55分TLE(原來寫的非遞歸伸展樹),然後對着別人AC代碼調了好幾天,才發現原來是我寫的伸展樹太慢了…… 後來經過一番折騰,改成了普通指針樹堆,平衡樹速度終於夠了,但在uoj 上還是95分TLE。我做了半天無用功,然後發現一個AC程序在本機跑得比我的還慢,重評測之後才85分,這才意識到是uoj 評測機本身的問題,然後我就放棄了修改。最後還是把語言換成C++11卡過去的……
這本來是一道動態點分治好題,結果被我硬生生弄成了 伸展樹練習+樹堆練習+指針練習+宏定義練習+靜態調試練習+……
附代碼讓大家感受一下我的調試過程

#include<ctime>   
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<sys/time.h>
using namespace std;
typedef long long ll;
#define OJ
//#define TM
//#define TM2
ll ctime()
{
#ifdef TM
    return clock();
#else
#ifdef TM2
    return clock();
#else
    return 0LL;
#endif
#endif
}
inline ll rd()
{
    static ll r, c;
    for(r=0;(c=getchar())<48||57<c;);
    for(;c>47&&58>c; r=10*r+c-48, c=getchar());
    return r;
}
ll wr(ll x)
{
    if(x/10) wr(x/10);
    putchar(48+x%10);
}
inline ll maxx(ll &x, ll y) {x<y?x=y:0;}

const ll mxn=100008;
ll n, cte, ans=0, r[mxn];
struct edge{ll v, c; edge *o;} e[mxn<<1], *h[mxn];
inline ll ae(ll u, ll v, ll c)
{
    (e[++cte]=
        (edge){v, c, h[u]}, h[u]=e+cte);
}
#define forv for(i=u[h]; i&&(v=i->v); i=i->o)

//---------------------LCA---------------------
struct lca
{
    const static ll mxlg=18;
    ll dp[mxn], f[mxn][mxlg], ds[mxn];
    ll sec, del;//time
    ll init(ll u)
    {
//      del=ctime();//time
        for(ll i=0, v; v=u[f][i]; ++i)
            u[f][i+1]=v[f][i];
//      sec+=ctime()-del;//time
    }
    inline ll dis(ll u, ll v)
    {
//      del=ctime();//time
        static ll i, w, x, y; x=u, y=v,
        dp[u]<dp[v]?u^=v^=u^=v:0;
        for(i=mxlg-1; dp[u]-dp[v]; --i)
            dp[u]-dp[v]&1<<i?u=f[u][i]:0;
        for(i=mxlg-1; f[u][0]^f[v][0]; --i)
            f[u][i]^f[v][i]?
                u=f[u][i], v=f[v][i]:0;
        w=u^v?f[u][0]:u;
//      sec+=ctime()-del;//time
        return ds[x]+ds[y]-2*ds[w];
    }
} l;
//---------------------LCA---------------------

//---------------------splay-------------------
struct spl
{
    const static ll mxnd=20000006;
    ll f[mxnd], s[mxnd][2],
        c[mxnd], siz[mxnd], cnt[mxnd],
        nd, t, st[mxnd];//w=upperbound
//  ll sec, del, cnto;//time

    inline ll mt(ll u)
        {u[siz]=u[s][0][siz]+u[s][1][siz]+u[cnt];}//VI
    inline ll rtt(ll u)
    {
        static ll v, w, k;
        v=f[u], k=v[s][1]==u,
        (w=u[f]=v[f])?w[s][w[s][1]==v]=u:0,
        (v[s][k]=u[s][!k])?v[s][k][f]=v:0,
        (u[s][!k]=v)[f]=u,
        mt(v), mt(u);
    }
    inline ll splay(ll u)
    {
        static ll v, w;
        for(;v=u[f]; rtt(u))
            (w=v[f])?rtt(v[s][0]==u^
                w[s][0]==v?u:v):0;
    }
    inline ll nw1(ll &u, ll v=0)
        {return s[u=++nd][0]=s[u][1]=
            siz[u]=cnt[u]=0, f[u]=v, u;}
    inline ll nw2(ll u, ll x)
        {return ++siz[u], ++cnt[u], c[u]=x, u;}
    inline ll ins(ll &u, ll x)
    {
        static ll v;
        for(v=u; v&&c[u]^x;)
            u=v, v=v[s][v[c]<=x];
        u?splay(c[u]^x?
            u[s][c[u]<x]=nw1(v, u):(v=u)):
            nw1(v), nw2(u=v, x);
    }
    inline ll sum(ll &u, ll x)
    {
        static ll v;
        for(v=u; v&&c[u]^x;)
            u=v, v=v[s][v[c]<=x];
        return splay(u),
            u[s][0][siz]+(u[c]<=x?u[cnt]:0);
    }//VI

    ll erase(ll u)
    {
        u?(erase(u[s][0]), erase(u[s][1]),
            st[t++]=u):0;
    }
    inline ll clear(ll u)
    {
//      del=ctime();//time
        erase(u);
//      sec+=ctime()-del;//time
    }
};
//---------------------splay-------------------

//---------------------treap-------------------
struct node
{
    node *s[2];
    ll c, ky, siz, cnt;
};
struct tre
{
    const static ll mxnd=10000006;
    node t[mxnd], *st[mxnd];
    ll nd, tp;
    inline node* mt(node *&u)
        {return u->siz=u->cnt+
            (u->s[0]?u->s[0]->siz:0)+
            (u->s[1]?u->s[1]->siz:0), u;}//VI
    inline node* rtt(node *&u, ll k)
    {
//      printf("rotate:\n%d\n", u);
        static node *v;
        return u->s[k]=(v=u->s[k])->s[!k],
            v->s[!k]=u, mt(u), mt(u=v);
    }
    inline node* nw1(node *&u, ll x)
        {return u=tp?st[--tp]:++nd+t,
            *u=(node){0, 0, x, rand(), 1, 1}, u;}
    inline node* nw2(node *&u)
        {return ++u->siz, ++u->cnt, u;}
    #define ku (u->c<=x)
    node* ins(node *&u, ll x)
    {
        if(!u) return nw1(u, x);
        if(u->c==x) return nw2(u);
        ll k=ku;
        ins(u->s[k], x);
        if(u->s[k]->ky<u->ky) rtt(u, k);
        else mt(u);
    }
    ll sum(node *u, ll x)
    {
        if(!u) return 0;
        ll k=ku;
        return sum(u->s[k], x)+
            (k?(u->s[0]?u->s[0]->siz:0)+
                u->cnt:0);
    }

    ll clear(node *u)
    {
        u?(clear(u->s[0]), clear(u->s[1]),
            st[tp++]=u):0;
    }
} s;
//---------------------treap-------------------

//---------------------點分治建樹--------------
struct ppt
{
    ll m, rt, fa, csrt,
        dep[mxn], sz[mxn], fat[mxn],
        t, st[mxn];
    node *st1[mxn], *st2[mxn];//splay tree 1 and 2
//  ll cntc;//time

    ll grt(ll u, ll f)
    {
        edge *i; ll v, csu=0; sz[u]=1;
        forv if(v^f&&!dep[v]) grt(v, u),
            sz[u]+=sz[v], maxx(csu, sz[v]);
        maxx(csu, m-sz[u]);
        if(csu<csrt) rt=u, fa=f, csrt=csu;//VI
    }
    ll dfs(ll u, ll f, ll d)
    {
        edge *i; ll v; st[t++]=d-r[u];
        forv if(v^f&&!dep[v])
            dfs(v, u, d+i->c);
    }

    inline ll ins(node *&x, node *&y)
    {
        for(y=0; t;)
            s.ins(x, st[--t]),
            s.ins(y, st[t]);
    }
    ll build(ll u, ll f, ll d, node *st)
    {
        edge *i; ll v; m=sz[u], csrt=~(1<<31), grt(u, 0),
    #ifdef TM
//      printf("bui:%I64d %I64d\n", u, rt),
    #endif
        fa?sz[fa]=m-sz[u=rt]:0, sz[u]=m,//VI
        dep[u]=d, fat[u]=f,//VI
        s.ins(st1[u]=0x0, -r[u]), st2[u]=st;//VI
        forv if(!dep[v]) dfs(v, 0, i->c),
            ins(st1[u], st2[v]=0x0);
        forv if(!dep[v])
            build(v, u, d+1, st2[v]);
    }

    ll clear(ll u, ll f, ll d)
    {
//      ++cntc;//time
        edge *i; ll v; dep[u]=0, s.clear(st1[u]),
            d<=u[fat][dep]?s.clear(st2[u]):0;
        forv if(v^f&&d<=dep[v])
            clear(v, u, d);
    }
} p;
//---------------------點分治建樹--------------

//---------------------動態點分治--------------
const double q=0.88;
#define stk (k^1?p.st2:p.st1)
inline ll qry(ll u, ll v, ll d, ll k)
    {return s.sum(v[stk], r[u]-d);}
inline node* ins(ll u, ll v, ll d, ll k)
    {return s.ins(v[stk], d-r[u]);}
ll cntr;
//ll sec, sec2, del;//time
inline ll gans(ll u)
{
#ifdef TM
    cntr=0;
    printf("(%I64d)\n", ctime());
#endif
    static ll v, w, d;
    for(v=u, w=0; v; w=v, v=v[p.fat])
    #ifdef TM
        ++cntr,
    #endif
        ++p.sz[v], d=l.dis(u, v),//VI
        ans+=qry(u, v, d, 1)-qry(u, w, d, 2),//v->w->>>u
        ins(u, v, d, 1), w&&ins(u, w, d, 2);

    wr(ans), putchar('\n');
#ifdef TM
    printf("{%I64d, %I64d}\n", l.sec, s.sec);
    printf("[%I64d]\n", cntr);
    printf("(%I64d)\n\n", ctime());
#endif

    for(v=w=0; u; w=u, u=p.fat[u])
        p.sz[w]>q*p.sz[u]?v=u:0;
    v?(
//      puts("rebuild"),
    #ifdef TM
        del=ctime(),//time
    #endif
        p.clear(v, 0, w=p.dep[v]),
    #ifdef TM
        sec2+=ctime()-del,//time
    #endif
        p.build(v, p.fat[v], w, p.st2[v])
    #ifdef TM
        , printf("af:%d\n\n", sec+=ctime()-del)//time
    #endif
    ):0;
}
//---------------------動態點分治--------------
inline ll add(ll u, ll f, ll c, ll ru)
{
    ae(u, f, c), ae(f, u, c), r[u]=ru,//VI L
    l.f[u][0]=f, l.dp[u]=l.dp[f]+1,//VI L
    l.ds[u]=l.ds[f]+c, l.init(u),//VI L
    p.fat[u]=f, p.dep[u]=p.dep[f]+1;//VI P
}
namespace debug
{
    static ll sz[mxn], i, k;
    ll chk(ll u)
    {
//      if(!u) return 0LL;
//      if(u[s.s][0]&&u[s.s][0][s.c]>=u[s.c]||
//          u[s.s][1]&&u[s.c]>=u[s.s][1][s.c]) return 1LL;
//      if(u[s.s][0][s.siz]+u[s.s][1][s.siz]+u[s.cnt]!=u[s.siz]) return 1LL;
//      return chk(u[s.s][0])|chk(u[s.s][1]);
    }
    inline ll chk()
    {
//      for(i=1; i<=n; ++i)
//          sz[i]=1;
//      for(i=1; i<=n; ++i)
//          sz[p.fat[i]]+=p.sz[i];
//      for(i=1; i<=n; ++i)
//          printf("%I64d:%I64d %I64d\n", i, p.sz[i], sz[i]);
//      for(i=1; i<=n; ++i)
//          printf("%I64d->%I64d\n", i, i[p.fat]);
//      for(k=0, i=1; i<=3243; ++i)
//          k|=chk(p.st1[i])|chk(p.st2[i]);
//      printf("k:%I64d\n", k);
//      printf("%d %d %d\n", s.siz[0], s.c[0], s.cnt[0]);
    }
}
int main()
{
#ifndef OJ
    using namespace debug;
    freopen("55.in", "r", stdin);
    freopen("55-1.out", "w", stdout);
#endif
    srand(666233);
    ll i, a, c, r;
    rd(), n=rd();
    for(i=1; i<=n; ++i)
    {
        a=rd()
    #ifdef OJ
        ^ans%1000000000
    #endif
        , c=rd(), r=rd(),
        add(i, a, c, r),
    #ifdef TM
        printf("case:%d\n{\n", i),
    #endif
        gans(i);
    #ifdef TM
        printf("}\n", i);
    #endif
    }
#ifndef OJ
#ifdef TM
    freopen("CON", "w", stdout);
    cout<<ctime()<<"\n";
    cout<<"l:"<<l.sec<<"\ns:"<<s.sec<<"\np:"<<sec<<"\np2:"<<sec2<<"\nc:"<<p.cntc<<"\n";
    p.sz[1]=n, p.clear(1, 0, 1); sec=ctime();
    ll x=s.cnto, y=s.sec;
    p.build(1, 0, 1, 0);
    printf("b:%I64d\ns:%I64d\no:%I64d\n",
        ctime()-sec, s.sec-y, s.cnto-x); chk();
#else
#ifdef TM2
    freopen("CON", "w", stdout);
    cout<<ctime()<<"\n";
#endif
#endif
#endif
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章