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); }