博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

2020智算之道复赛E 树数数

传送门

 

 

 

 

题意就懒得复述了

直接对着欧拉序建线段树,每个节点用一个堆来维护标记。

每次修改可能导致一部分区间被某个点覆盖,而且这个覆盖并不遵循后边的修改会覆盖前面的修改这样的规则,而是深度小的黑点优先于深度大的黑点,因此需要用堆来维护标记。由于区间只会完全包含,不会出现交叉的情况,可以标记永久化,删除也容易处理。

 

#include<stdio.h>
#include<cstring>
#include<queue>
#include<algorithm>
#define ll long long 
#define lx (x<<1)
#define rx ((x<<1)|1)
using namespace std;

char ibuf[20000004],*iptr=ibuf-1,C;
inline int _(){
    int x=0,c=*++iptr;
    while(c<48)c=*++iptr;
    while(c>47)x=x*10+c-48,c=*++iptr;
    return x;
}
inline int _char(){
    int x=0,c=*++iptr;
    while(c<'A')c=*++iptr;
    while(c>'A' && c<'Z')x=c,c=*++iptr;
    return x;
}
char obuf[5000000],*optr=obuf;
inline void _(ll x){
    static int stk[32],stp=0;
    if(!x)stk[stp++]=0;
    while(x)stk[stp++]=x%10,x/=10;
    while(stp)*(optr++)=stk[--stp]+48;
    *(optr++)=10;
}
const int MN = 210000;
struct na{int y,ne;}b[MN];
int n, m, num=0, f[MN], w[MN], l[MN], si[MN], L[MN], R[MN], pdf[MN], order = 0, color[MN], deep[MN];
ll lose[MN<<2];
ll ans[MN<<2];
ll co[MN];
priority_queue<int> tag[MN<<2];
pair<ll, ll> pair_add(pair<ll, ll> a, pair<ll, ll> b){
    return make_pair(a.first+b.first, a.second+b.second);
}
inline void in(int x,int y){b[++num].y=y;b[num].ne=l[x];l[x]=num;}
void dfs1(int x){
    si[x] = 1;
    L[x] = ++order;
    pdf[order] = x;
    for (int i = l[x]; i; i = b[i].ne){
        dfs1(b[i].y);
        co[x] += 1ll*si[x]*si[b[i].y];
        si[x] += si[b[i].y];
    }
    R[x] = order;
}
void build(int x, int l, int r){
    if (l == r){
        lose[x] = co[pdf[l]];
        return;
    }
    int mid = l+r>>1;
    build(lx, l ,mid);
    build(rx, mid+1, r);
    lose[x] = lose[lx]+lose[rx];
}
void update(int x, int l, int r){
    if (l == r){
        ans[x] = 0;
        lose[x] = co[pdf[l]];
    }else{
        ans[x] = ans[lx] + ans[rx];
        lose[x] = lose[lx] + lose[rx];
    }
    
    while(tag[x].size() && (!color[tag[x].top()])) tag[x].pop();
    if (tag[x].size()){
        ans[x] += lose[x] * w[tag[x].top()];
        lose[x] = 0;
    }
}
pair<ll, ll> ask(int x, int l, int r, int L, int R){
    if (l == L && r == R){
        return make_pair(ans[x], lose[x]);
    }
    int mid = l+r>>1;
    pair<ll, ll> res;
    if (R <= mid){
        res = ask(lx, l, mid, L, R);
    }else if (L > mid){
        res = ask(rx, mid+1, r, L, R);
    }else{
        res = pair_add(ask(lx, l, mid, L, mid), ask(rx, mid+1, r, mid+1, R));
    }
    while(tag[x].size() && (!color[tag[x].top()])) tag[x].pop();
    if (tag[x].size()){
        res.first += res.second * w[tag[x].top()];
        res.second = 0;
    }
    return res;
}
void addTag(int x, int l, int r, int L, int R, int p){
    if (l == L && r == R){
        if (color[p]){
            tag[x].push(p);
        }
        update(x, l, r);
        return;
    }
    int mid = l + r >> 1;
    if (R <= mid){
        addTag(lx, l, mid, L, R, p);
    }else if (L > mid){
        addTag(rx, mid+1, r, L, R, p);
    }else{
        addTag(lx, l, mid, L, mid, p);
        addTag(rx, mid+1, r, mid+1, R, p);
    }
    update(x, l, r);
}
int main(){
    ibuf[fread(ibuf,1,20000000,stdin)]=0;
    n = _();
    m = _();
    for (int i = 2; i <= n; i++) f[i] = _(), in(f[i], i);
    for (int i = 1; i <= n; i++) w[i] = _();
    dfs1(1);
    build(1, 1, n);
    while (m--){
        char s = _char();
        if (s == 'Q'){
            int x = _();
            _(ask(1, 1, n, L[x], R[x]).first);
        }else if (s == 'F'){
            int x = _();
            color[x]^=1;
            addTag(1, 1, n, L[x], R[x], x);
        }else if (s == 'M'){
            int x = _();
            w[x] = _();
            if (color[x]){
                addTag(1, 1, n, L[x], R[x], 0);
            }
        }
    }
    fwrite(obuf,1,optr-obuf,stdout);
}
View Code

 

posted @ 2020-08-09 18:55  swm_sxt  阅读(370)  评论(0编辑  收藏  举报