【树链剖分(区间线段树)】BZOJ4196-[NOI2015]软件包管理
【题目大意】
如果软件包A依赖软件包B,那么安装软件包A以前,必须先安装软件包B。同时,如果想要卸载软件包B,则必须卸载软件包A。而且,由于你之前的工作,除0号软件包以外,在你的管理器当中的软件包都会依赖一个且仅一个软件包,而0号软件包不依赖任何一个软件包。依赖关系不存在环。求出在安装和卸载某个软件包时,实际上会改变多少个软件包的安装状态(即安装操作会安装多少个未安装的软件包,或卸载操作会卸载多少个已安装的软件包。(注意,安装一个已安装的软件包,或卸载一个未安装的软件包,都不会改变任何软件包的安装状态,即在此情况下,改变安装状态的软件包数为0)
【思路】
裸的树剖...然而我发现我写错了区间覆盖的线段树,要设置两个标记,一个记录该区间是否需要修改,另一个记录该区间覆盖的值。
话说BZOJ要用printf否则会RE,我怎么不长记性呢………
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<vector> 6 #define lson l,m,rt<<1 7 #define rson m+1,r,rt<<1|1 8 using namespace std; 9 const int MAXN=100000+50; 10 const int rt=0; 11 vector<int> E[MAXN]; 12 int n; 13 int fa[MAXN],dep[MAXN],hson[MAXN],size[MAXN]; 14 int cnt=0,top[MAXN],pos[MAXN]; 15 int sum[MAXN<<3],add[MAXN<<3],change[MAXN<<3]; 16 17 //树链剖分部分 18 void addedge(int u,int v) 19 { 20 E[u].push_back(v); 21 } 22 23 void dfs1(int u,int father,int depth) 24 { 25 fa[u]=father; 26 dep[u]=depth; 27 size[u]=1; 28 hson[u]=-1; 29 for (int i=0;i<E[u].size();i++) 30 { 31 int to=E[u][i]; 32 dfs1(to,u,depth+1); 33 size[u]+=size[to]; 34 if (hson[u]==-1 || size[to]>size[hson[u]]) hson[u]=to; 35 } 36 } 37 38 void dfs2(int u,int t) 39 { 40 pos[u]=++cnt; 41 top[u]=t; 42 if (hson[u]!=-1) dfs2(hson[u],t); 43 for (int i=0;i<E[u].size();i++) 44 { 45 int to=E[u][i]; 46 if (to!=hson[u]) dfs2(to,to); 47 } 48 } 49 50 //线段树部分 51 void build() 52 { 53 memset(sum,0,sizeof(sum)); 54 memset(add,0,sizeof(add)); 55 } 56 57 void pushup(int rt) 58 { 59 sum[rt]=sum[rt<<1]+sum[rt<<1|1]; 60 } 61 62 void pushdown(int rt,int m) 63 { 64 if (change[rt]) 65 { 66 change[rt<<1]=change[rt<<1|1]=1; 67 add[rt<<1]=add[rt]; 68 add[rt<<1|1]=add[rt]; 69 sum[rt<<1]=add[rt]*(m-(m>>1)); 70 sum[rt<<1|1]=add[rt]*(m>>1); 71 add[rt]=change[rt]=0; 72 } 73 } 74 75 int query_sum(int L,int R,int l,int r,int rt) 76 { 77 if (L<=l && r<=R) return sum[rt]; 78 pushdown(rt,r-l+1); 79 int m=(l+r)>>1; 80 int ret=0; 81 if (m>=L) ret+=query_sum(L,R,lson); 82 if (m<R) ret+=query_sum(L,R,rson); 83 pushup(rt); 84 return ret; 85 } 86 87 void modify(int L,int R,int l,int r,int rt,int x) 88 { 89 if (L<=l && r<=R) 90 { 91 change[rt]=1; 92 add[rt]=x; 93 sum[rt]=(r-l+1)*x; 94 return; 95 } 96 pushdown(rt,r-l+1); 97 int m=(l+r)>>1; 98 if (m>=L) modify(L,R,lson,x); 99 if (m<R) modify(L,R,rson,x); 100 pushup(rt); 101 } 102 103 //树链剖分查询部分 104 int install(int x,int y) 105 { 106 int ret=dep[x],f1=top[x],f2=top[y]; 107 while (f1!=f2) 108 { 109 ret-=query_sum(pos[f1],pos[x],1,n,1); 110 modify(pos[f1],pos[x],1,n,1,1); 111 x=fa[f1]; 112 f1=top[x]; 113 } 114 ret-=query_sum(pos[y],pos[x],1,n,1); 115 modify(pos[y],pos[x],1,n,1,1); 116 return (ret); 117 } 118 119 int uninstall(int x) 120 { 121 int ret=query_sum(pos[x],pos[x]+size[x]-1,1,n,1); 122 modify(pos[x],pos[x]+size[x]-1,1,n,1,0); 123 return ret; 124 } 125 126 127 //读入部分 128 void init() 129 { 130 scanf("%d",&n); 131 for (int i=1;i<n;i++) 132 { 133 int tmp; 134 scanf("%d",&tmp); 135 addedge(tmp,i); 136 } 137 dfs1(0,0,1); 138 dfs2(0,0); 139 } 140 141 void get_ans() 142 { 143 memset(sum,0,sizeof(sum)); 144 memset(change,0,sizeof(change)); 145 memset(add,0,sizeof(add)); 146 int q; 147 scanf("%d",&q); 148 for (int i=0;i<q;i++) 149 { 150 char str[25]; 151 int x; 152 scanf("%s%d",str,&x); 153 if (str[0]=='i') printf("%d\n",install(x,rt)); 154 else if (str[0]=='u') printf("%d\n",uninstall(x)); 155 } 156 } 157 158 int main() 159 { 160 init(); 161 build(); 162 get_ans(); 163 return 0; 164 }