[BZOJ3786]星系探索(dfs序+splay)

来源:互联网 发布:现在什么软件翻墙好 编辑:程序博客网 时间:2024/06/06 06:52

题目描述

传送门

题目大意:给出一棵树,支持几个操作:Q x询问点x到根的路径上的点的权值和;C x y将以x为根的子树接到y上;F x y以x为根的子树中的每个点的权值加y

题解

这题卡数组…必须写结构体或者指针的splay才能过
首先将这棵树按照dfs序展开,对于每一个点维护一个入栈点和一个出栈点,入栈点的权值为点权,出栈点的权值为点权的相反数
用splay来维护这个dfs序列,对于Q操作,其实就是将区间[in(1),in(x)]提取,然后求权值和,不需要的权值会正负抵消;对于C操作,就是讲[in(x),out(x)]区间提取出来接到out(y)的前面;对于F操作,就是将[in(x),out(x)]提取然后区间修改

代码

#include<algorithm>#include<iostream>#include<cstring>#include<cstdio>#include<cmath>using namespace std;#define N 200005#define LL long longint n,m,dfs_clock,root;int a[N],in[N],out[N],pt[N],tot,point[N],nxt[N],v[N];bool isin[N];struct data{    int f,ch[2],pos,neg;    LL key,sum,delta;}tr[N];void add(int x,int y){    ++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;}void dfs(int x,int fa){    in[x]=++dfs_clock;pt[dfs_clock]=x;    isin[dfs_clock]=1;    for (int i=point[x];i;i=nxt[i])        if (v[i]!=fa)            dfs(v[i],x);    out[x]=++dfs_clock;pt[dfs_clock]=x;}void update(int x){    if (!x) return;    if (isin[x]) tr[x].pos=1,tr[x].neg=0;    else tr[x].pos=0,tr[x].neg=1;    tr[x].sum=tr[x].key;    int l=tr[x].ch[0],r=tr[x].ch[1];    if (l) tr[x].sum+=tr[l].sum,tr[x].pos+=tr[l].pos,tr[x].neg+=tr[l].neg;    if (r) tr[x].sum+=tr[r].sum,tr[x].pos+=tr[r].pos,tr[x].neg+=tr[r].neg;}void pushdown(int x){    if (x&&tr[x].delta)    {        int l=tr[x].ch[0],r=tr[x].ch[1];        LL del=tr[x].delta;        if (l)        {            if (isin[l]) tr[l].key+=del;            else tr[l].key-=del;            tr[l].sum+=del*(tr[l].pos-tr[l].neg);            tr[l].delta+=del;        }        if (r)        {            if (isin[r]) tr[r].key+=del;            else tr[r].key-=del;            tr[r].sum+=del*(tr[r].pos-tr[r].neg);            tr[r].delta+=del;        }        tr[x].delta=0;    }}int build(int l,int r,int fa){    if (l>r) return 0;    int mid=(l+r)>>1;    tr[mid].f=fa;    if (isin[mid]) tr[mid].key=(LL)a[pt[mid]];    else tr[mid].key=-(LL)a[pt[mid]];    int lch=build(l,mid-1,mid);    int rch=build(mid+1,r,mid);    tr[mid].ch[0]=lch,tr[mid].ch[1]=rch;    update(mid);    return mid;}int get(int x){    return tr[tr[x].f].ch[1]==x;}void rotate(int x){    int old=tr[x].f,oldf=tr[old].f,wh=get(x);    pushdown(oldf);    pushdown(old);    pushdown(x);    tr[old].ch[wh]=tr[x].ch[wh^1];    if (tr[old].ch[wh]) tr[tr[old].ch[wh]].f=old;    tr[x].ch[wh^1]=old;    tr[old].f=x;    if (oldf) tr[oldf].ch[tr[oldf].ch[1]==old]=x;    tr[x].f=oldf;    update(old);    update(x);}void splay(int x,int tar){    for (int fa;(fa=tr[x].f)!=tar;rotate(x))        if (tr[fa].f!=tar)            rotate((get(fa)==get(x))?fa:x);    if (!tar) root=x;}int PRE(int x){    splay(x,0);    x=tr[root].ch[0];    while (tr[x].ch[1]) x=tr[x].ch[1];    return x;}int NEXT(int x){    splay(x,0);    x=tr[root].ch[1];    while (tr[x].ch[0]) x=tr[x].ch[0];    return x;}int main(){    scanf("%d",&n);    for (int i=2;i<=n;++i)    {        int fa;scanf("%d",&fa);        add(fa,i);    }    for (int i=1;i<=n;++i) scanf("%d",&a[i]);    ++dfs_clock;    dfs(1,0);    ++dfs_clock;    root=build(1,dfs_clock,0);    scanf("%d",&m);    while (m--)    {        char opt=getchar();        while (opt!='Q'&&opt!='C'&&opt!='F') opt=getchar();        if (opt=='Q')        {            int x;scanf("%d",&x);            int aa=NEXT(in[x]);            splay(1,0);            splay(aa,1);            LL ans=tr[tr[tr[root].ch[1]].ch[0]].sum;            printf("%lld\n",ans);        }        else if (opt=='C')        {            int x,y,now;scanf("%d%d",&x,&y);            int aa=PRE(in[x]),bb=NEXT(out[x]);            splay(aa,0);            splay(bb,aa);            now=tr[tr[root].ch[1]].ch[0];            tr[now].f=0;tr[tr[root].ch[1]].ch[0]=0;            update(tr[root].ch[1]);            update(root);            aa=PRE(out[y]);            splay(aa,0);            splay(out[y],aa);            tr[now].f=tr[root].ch[1];tr[tr[root].ch[1]].ch[0]=now;            update(tr[root].ch[1]);            update(root);        }        else        {            int x,y,now;scanf("%d%d",&x,&y);            int aa=PRE(in[x]),bb=NEXT(out[x]);            splay(aa,0);            splay(bb,aa);            now=tr[tr[root].ch[1]].ch[0];            if (isin[now]) tr[now].key+=(LL)y;            else tr[now].key-=(LL)y;            tr[now].sum+=(LL)y*(tr[now].pos-tr[now].neg);            tr[now].delta+=(LL)y;            update(tr[root].ch[1]);            update(root);        }    }}
0 0
原创粉丝点击