bzoj3786: 星系探索

传送门

一个裸的splay维护括号序列的题。

跟弹飞绵羊几乎一毛一样,只需把进栈的点权值设为w,出栈点权值设为-w即可。

多了一个子树加的操作,就把子树split出来,打上标记再merge回去就好了。

//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<queue>
#include<cmath>
const int N=600007;
typedef long long LL;
using namespace std;
int n,m,val[N];
char o[10];

template<typename T>void read(T &x)  {
    char ch=getchar(); x=0; T f=1;
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') f=-1,ch=getchar();
    for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
}

int ecnt,fir[N],nx[N],to[N];
void add(int u,int v) {
    nx[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v;
}

int dfn[2][N],v[N],f[N],dfs_clock,tot;
void dfs(int x) {
    dfn[0][x]=++dfs_clock;
    v[dfn[0][x]]=val[x];
    f[dfn[0][x]]=1;
    for(int i=fir[x];i;i=nx[i]) 
        dfs(to[i]);
    dfn[1][x]=++dfs_clock;
    v[dfn[1][x]]=-val[x];
    f[dfn[1][x]]=-1;
}

int p[N],ch[N][2];
LL sum[N],sumf[N],lz[N];
#define lc ch[x][0]
#define rc ch[x][1] 
void update(int x) { 
    sum[x]=(LL)v[x]+sum[lc]+sum[rc];
    sumf[x]=(LL)f[x]+sumf[lc]+sumf[rc]; 
}

void ADD(int x,int w) {
    v[x]+=(LL)f[x]*w;
    sum[x]+=sumf[x]*w;
    lz[x]+=w;
}

void down(int x) {
    if(!lz[x]) return;
    if(lc) ADD(lc,lz[x]); 
    if(rc) ADD(rc,lz[x]);
    lz[x]=0;
}

int build(int sz) {
    if(!sz) return 0;
    int ls,rs,x;
    ls=build(sz>>1);
    x=++tot;
    rs=build(sz-(sz>>1)-1);
    if(ls) p[ls]=x; lc=ls;
    if(rs) p[rs]=x; rc=rs;
    update(x);
    return x;
}

void rotate(int x) {
    int y=p[x],z=p[y],l=(x==ch[y][1]),r=l^1;
    if(z) ch[z][y==ch[z][1]]=x; p[x]=z;
    ch[y][l]=ch[x][r]; p[ch[x][r]]=y;
    ch[x][r]=y; p[y]=x;
    update(y); update(x);
}

void splay(int x,int FA=0) {
    static int g[N],top=0,tp;
    for(tp=x;tp!=FA;tp=p[tp]) g[++top]=tp;
    g[++top]=tp;
    while(top) down(g[top--]);
    for(;p[x]!=FA;rotate(x)) {
        int y=p[x],z=p[y];
        if(z!=FA) ((x==ch[y][1])^(y==ch[z][1]))?rotate(x):rotate(y); 
    } 
}

int pre(int x) {
    splay(x); x=lc;
    while(rc) x=rc;
    return x;
}

int nxt(int x) {
    splay(x); x=rc;
    while(lc) x=lc;
    return x;
}

int split(int x) {//x为左边 最后一个 
    splay(x); int y=rc; 
    rc=p[y]=0; 
    update(x); return y;
}

void merge(int x,int y) {
    splay(x); splay(y);
    while(rc) x=rc; splay(x);
    rc=y; p[y]=x; update(x);
}

int main() {
#ifdef DEBUG
    freopen(".in","r",stdin);
    freopen(".out","w",stdout);
#endif
    read(n);
    for(int i=2;i<=n;i++) {
        int fa; read(fa);
        add(fa,i);
    }
    for(int i=1;i<=n;i++) read(val[i]);
    dfs(1);
    int x=2*n+1,y=2*n+2;
    ch[x][1]=y; p[y]=x;
    ch[y][0]=build(2*n); p[ch[y][0]]=y;
    update(y); update(x);
    read(m);
    while(m--) {
        scanf("%s",o);
        int x,y,w; read(x);
        if(o[0]=='Q') {
            int z=nxt(dfn[0][x]);
            splay(z);
            printf("%lld\n",sum[ch[z][0]]);
        }
        else if(o[0]=='C') {
            read(y);
            int l=pre(dfn[0][x]);
            split(l);
            int r=split(dfn[1][x]);
            merge(l,r);
            split(dfn[0][y]);
            merge(dfn[0][y],dfn[0][x]);
            merge(dfn[0][x],dfn[1][y]);
        }
        else if(o[0]=='F') {
            read(w);
            int l=pre(dfn[0][x]);
            split(l);
            int r=split(dfn[1][x]);
            splay(dfn[0][x]);
            ADD(dfn[0][x],w);
            merge(l,dfn[0][x]);
            merge(dfn[0][x],r);
        }
    }
    return 0;
}
/*
3
1
1
4 5 7
5
Q 2
F 1 3
Q 2
C 2 3
Q 2
*/
View Code

·

posted @ 2018-03-10 11:08  啊宸  阅读(164)  评论(2编辑  收藏  举报