NOI2015 软件包管理器
最近学了树剖我们来做几道题练练手。
这个题我觉得也是板子题啊……
反正就是对于一个安装操作,就在它自己所在链向上跳,如果当前链顶已经被安装的话计算一下从这个点到链顶还有多少没被安装即可。每次向上跳的时候都要把经过的链上的点全改为1.至于卸载操作就更简单了,直接先统计自己子树内有多少节点值为1的儿子(已安装软件),之后区间修改为0即可。如果这个点已经被安装/卸载相对应的就可以不执行这次操作。
这题还是很好写的,一次AC。(之后就是树剖无限bug的开始)
看一下代码。
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<cmath> #include<queue> #include<set> #define rep(i,a,n) for(int i = a;i <= n;i++) #define per(i,n,a) for(int i = n;i >= a;i--) #define enter putchar('\n') using namespace std; typedef long long ll; const int M = 100005; int read() { int ans = 0,op = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') op = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { ans *= 10; ans += ch - '0'; ch = getchar(); } return ans * op; } struct seg { int v,lazy; }t[M<<2]; struct edge { int next,to,from; }e[M<<1]; int n,dfn[M],rk[M],a[M],size[M],dep[M],fa[M],hson[M],q,x,y,head[M],ecnt,idx,top[M]; char s[15]; void add(int x,int y) { e[++ecnt].to = y; e[ecnt].from = x; e[ecnt].next = head[x]; head[x] = ecnt; } void dfs1(int x,int f,int depth) { size[x] = 1,dep[x] = depth,fa[x] = f; int maxson = -1; for(int i = head[x];i;i = e[i].next) { if(e[i].to == f) continue; dfs1(e[i].to,x,depth+1); size[x] += size[e[i].to]; if(size[e[i].to] > maxson) maxson = size[e[i].to],hson[x] = e[i].to; } } void dfs2(int x,int t) { dfn[x] = ++idx,top[x] = t; if(!hson[x]) return; dfs2(hson[x],t); for(int i = head[x];i;i = e[i].next) { if(e[i].to == fa[x] || e[i].to == hson[x]) continue; dfs2(e[i].to,e[i].to); } } void build(int p,int l,int r) { if(l == r) { t[p].lazy = -1; return; } int mid = (l+r) >> 1; build(p<<1,l,mid),build(p<<1|1,mid+1,r); } void pushdown(int p,int l,int r) { int mid = (l+r) >> 1; t[p<<1].lazy = t[p].lazy,t[p<<1|1].lazy = t[p].lazy; t[p<<1].v = t[p].lazy * (mid-l+1),t[p<<1|1].v = t[p].lazy * (r-mid); t[p].lazy = -1; } int query(int p,int l,int r,int kl,int kr) { if(l == kl && r == kr) return t[p].v; int mid = (l+r) >> 1; if(t[p].lazy != -1) pushdown(p,l,r); if(kr <= mid) return query(p<<1,l,mid,kl,kr); else if(kl > mid) return query(p<<1|1,mid+1,r,kl,kr); else return query(p<<1,l,mid,kl,mid) + query(p<<1|1,mid+1,r,mid+1,kr); } void modify(int p,int l,int r,int kl,int kr,int val) { if(l == kl && r == kr) { t[p].lazy = val,t[p].v = val * (r-l+1); return; } int mid = (l+r) >> 1; if(t[p].lazy != -1) pushdown(p,l,r); if(kr <= mid) modify(p<<1,l,mid,kl,kr,val); else if(kl > mid) modify(p<<1|1,mid+1,r,kl,kr,val); else modify(p<<1,l,mid,kl,mid,val),modify(p<<1|1,mid+1,r,mid+1,kr,val); t[p].v = t[p<<1].v + t[p<<1|1].v; } int qrange(int x) { int ans = 0; while(!query(1,0,n,dfn[top[x]],dfn[top[x]])) { ans += (dfn[x] - dfn[top[x]] + 1); modify(1,0,n,dfn[top[x]],dfn[x],1); x = fa[top[x]]; } int g = dfn[x] - dfn[top[x]] + 1; // printf("#%d %d\n",g,x); //printf("!%d\n",query(1,0,n,dfn[top[x]],dfn[x])); ans += (g - query(1,0,n,dfn[top[x]],dfn[x])),modify(1,0,n,dfn[top[x]],dfn[x],1); //printf("!%d\n",query(1,0,n,dfn[top[x]],5)); return ans; } int qson(int x) { int ans = 0; ans += query(1,0,n,dfn[x],dfn[x] + size[x] - 1); modify(1,0,n,dfn[x],dfn[x] + size[x] - 1,0); return ans; } int main() { n = read(); rep(i,1,n-1) x = read(),add(x,i),add(i,x); //rep(i,1,ecnt) printf("#%d %d\n",e[i].from,e[i].to); dfs1(0,0,1),dfs2(0,0),build(1,0,n); q = read(); while(q--) { scanf("%s",s); if(s[0] == 'i') { //printf("@%d\n",query(1,0,n,0,n)); x = read(); if(query(1,0,n,dfn[x],dfn[x])) { printf("0\n"); continue; } printf("%d\n",qrange(x)); } else if(s[0] == 'u') { x = read(); if(!query(1,0,n,dfn[x],dfn[x])) { printf("0\n"); continue; } printf("%d\n",qson(x)); } } return 0; }
当你意识到,每个上一秒都成为永恒。