bzoj 3786 星系探索 (splay+dfs序)

題目大意:給你一棵樹,支持一下三種操作

1.獲取某節點到根節點的路徑上所有節點的權值和

2.更換某棵子樹的父親

3.某子樹內所有節點的權值都增加一個值w

當時想到了splay維護dfs序,查完題解發現思路是對的,然後我就寫了足足6個小時才A

st[x]代表入棧時間,ed[x]代表出棧時間

對於第一個操作,每個樹上節點在splay中都有兩個位置,分別對應入棧出棧序,然後把入棧的點權*1,出棧點權*-1,就可以避免其它子樹幹擾了

接着查詢到根節點的路徑權值和呢,splay把1~st[x]整個序列都扔到一個子樹裏,求一下子樹權值和即可

第二個操作,可以找一下st[x]和ed[x]對應splay中節點的前驅和後繼,把它們都搞到一個splay子樹裏,在把整棵樹接到要求的父節點即可

第三個操作,和第二個操作類似,找前驅後繼然後在子樹打標記即可,此外,還要維護splay子樹內的入棧節點數-出棧節點數來直接得到splay子樹的權值和。

注意,一定要在所有能傳標記的地方都傳標記,不論是從下往上splay,還是從上到下找前驅or後繼,而如果不在找前驅後繼的過程中下傳標記,上層的標記無法被傳到下層,導致結果錯誤!就這個錯誤我調了2個小時!

#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 200100
#define il inline
#define ll long long 
#define root d[0].ch[1]
using namespace std;

char q[10];
int n,m,cte,tot;
int st[N],ed[N],head[N],sq[N];
ll w[N];
struct EDGE{int to,nxt;}edge[N];
struct SPLAY{int fa,ch[2],ss,fl;ll val,sum,tag;}d[N];
il int idf(int x){return d[d[x].fa].ch[0]==x?0:1;}
il void con(int x,int ff,int p){d[ff].ch[p]=x;d[x].fa=ff;}
il void pushup(int x){
    d[x].sum=d[d[x].ch[0]].sum+d[d[x].ch[1]].sum+d[x].val;
    d[x].ss=d[d[x].ch[0]].ss+d[d[x].ch[1]].ss+d[x].fl;
}
il void pushdown(int x){
    if(!d[x].tag) return;
    int ls=d[x].ch[0],rs=d[x].ch[1];
    d[ls].tag+=d[x].tag,d[rs].tag+=d[x].tag;
    d[ls].val+=d[x].tag*(ll)d[ls].fl,d[rs].val+=d[x].tag*(ll)d[rs].fl;
    d[ls].sum+=d[x].tag*(ll)d[ls].ss,d[rs].sum+=d[x].tag*(ll)d[rs].ss;
    d[x].tag=0;
}
il void rot(int x){
    int y=d[x].fa;int ff=d[y].fa;int px=idf(x);int py=idf(y);
    pushdown(y),pushdown(x);
    con(d[x].ch[px^1],y,px),con(y,x,px^1),con(x,ff,py);
    pushup(y),pushup(x);
}
il void splay(int x,int to){
    to=d[to].fa;
    while(d[x].fa!=to){
        int y=d[x].fa;
        if(d[y].fa==to) rot(x);
        else if(idf(x)==idf(y)) rot(y),rot(x);
        else rot(x),rot(x);}
}
int gc(){
    int rett=0,fh=1;char p=getchar();
    while(p<'0'||p>'9'){if(p=='-')fh=-1;p=getchar();}
    while(p>='0'&&p<='9'){rett=(rett<<3)+(rett<<1)+p-'0';p=getchar();}
    return rett*fh;
}
void ae(int u,int v){
    cte++;edge[cte].to=v;
    edge[cte].nxt=head[u];head[u]=cte;
}
void dfs1(int u,int ff)
{
    st[u]=++tot,sq[tot]=u,d[tot].val=w[u],d[tot].fl=1;
    for(int j=head[u];j!=-1;j=edge[j].nxt){
        int v=edge[j].to;
        if(v==ff) continue;
        dfs1(v,u);}
    ed[u]=++tot,sq[tot]=u,d[tot].val=-w[u],d[tot].fl=-1;
}
int build(int l,int r)
{
    if(l>r) return 0;
    int mid=(l+r)>>1;
    con(build(l,mid-1),mid,0);
    con(build(mid+1,r),mid,1);
    pushup(mid);
    return mid;
}
int lower(int x)
{
    pushdown(x),x=d[x].ch[0];
    while(x){
        pushdown(x);
        if(d[x].ch[1]) x=d[x].ch[1];
        else break;}
    return x;
}
int upper(int x)
{
    pushdown(x),x=d[x].ch[1];
    while(x){
        pushdown(x);
        if(d[x].ch[0]) x=d[x].ch[0];
        else break;}
    return x;
}
ll query(int x)
{
    splay(st[0],root);
    splay(st[x],d[root].ch[1]);
    int lw=upper(st[x]);
    splay(lw,d[root].ch[1]);
    return d[d[lw].ch[0]].sum;
}
void add(int x,ll ww)
{
    int trl,trr,rt;
    splay(st[x],root);
    splay(ed[x],d[root].ch[1]);
    trl=lower(st[x]);
    splay(trl,root);
    trr=upper(ed[x]);
    splay(trr,d[root].ch[1]);
    rt=d[trr].ch[0];
    d[rt].val+=ww*(ll)d[rt].fl;
    d[rt].sum+=ww*(ll)d[rt].ss;
    d[rt].tag+=ww;
}
void mov(int x,int y)
{
    int trl,trr,frt,rtt;
    splay(st[x],root);
    splay(ed[x],d[root].ch[1]);
    trl=lower(st[x]);
    splay(trl,root);
    trr=upper(ed[x]);
    splay(trr,d[root].ch[1]);
    pushdown(trl),pushdown(trr);
    rtt=d[trr].ch[0];
    d[trr].ch[0]=0,d[rtt].fa=0;
    pushup(trr),pushup(trl);
    
    splay(st[y],root);
    splay(ed[y],d[root].ch[1]);
    trl=lower(ed[y]);
    if(trl) con(rtt,trl,1);
    else con(rtt,ed[y],0);
    splay(rtt,root);
}
void print(int x)
{
    if(d[x].ch[0]) print(d[x].ch[0]);
    printf("%d ",sq[x]);
    if(d[x].ch[1]) print(d[x].ch[1]);
}

int main()
{
    scanf("%d",&n);
    int x,y;
    memset(head,-1,sizeof(head));
    for(int i=2;i<=n;i++)
        x=gc(),ae(x,i),ae(i,x);
    for(int i=1;i<=n;i++)
        w[i]=gc();
    st[0]=++tot,dfs1(1,-1),ed[0]=++tot;
    root=build(1,tot);
    scanf("%d",&m);
    for(int i=1;i<=m;i++){
        scanf("%s",q);
        if(q[0]=='Q'){
            x=gc();
            printf("%lld\n",query(x));
        }else if(q[0]=='F'){
            x=gc(),y=gc();
            add(x,(ll)y);
        }else{
            x=gc(),y=gc();
            mov(x,y);
        }
    }
    /*for(int i=1;i<=n;i++)
        printf("%lld %lld %lld\n",query(i),d[st[i]].val,d[ed[i]].val);*/
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章