[NOI2015]软件包管理器 树链剖分

~~~题面~~~

题解:

首先我们观察到0号不会依赖别人,而其他的软件都会依赖且仅会依赖一个软件。因此这是一棵树。

于是我们在看看要支持一些什么操作。

1,安装一个软件要改变多少软件的状态。

  如果将一个软件与所依赖的软件相连,那么可能要改变的状态就是它自己和往上走直到根的那条链上的点。

2,卸载一个软件要改变多少软件的状态

  显然是自己+子树。

那么我们可以想到什么呢?

树链剖分!

安装就查询从自己往上走的点中有多少已经被安装。

deep[x](deep[0] = 1)就是可能要改变的软件数,假设已经有k个被安装,那么要改变的软件数就是deep[x] - k

卸载就查询子树+自己中有多少已经安装了的,这个数量就是答案。

每次安装查询时都把查询的点赋为1,卸载时把所有涉及到的点赋为0,线段树维护

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define R register int
  4 #define AC 120000
  5 #define ac 600000//error ...所以说还是数组小了的锅么
  6 #define D printf("line in %d\n", __LINE__);
  7 int n, m, cnt, ans, w;
  8 int date[AC], Next[AC], Head[AC], tot;//因为是树,所以只要开这么大
  9 int son[AC], top[AC], father[AC], deep[AC], Size[AC], id[AC];
 10 int tree[ac], l[ac], r[ac], lazy[ac];//线段树开4倍吧
 11 char s[30];
 12 
 13 inline int read()
 14 {
 15     int x = 0; char c = getchar();
 16     while(c > '9' || c < '0') c = getchar();
 17     while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();//error !!! 读入优化写错了。。。。
 18     return x;
 19 }
 20 
 21 inline void add(int f, int w)
 22 {
 23     date[++tot] = w, Next[tot] = Head[f], Head[f] = tot;
 24 }
 25 
 26 void pre()//读入依赖关系, 因为编号从0开始, 所以整体往后顺延一个
 27 {
 28     n = read();//序号全部往后推一个, 但总数又不会变,,,,
 29     for(R i=2;i<=n;i++)
 30     {
 31         father[i] = read() + 1;
 32         add(father[i], i);
 33     }
 34     deep[1] = 1;
 35 }
 36 //Size包括自己
 37 void dfs1(int x)//get son && Size && deep
 38 {
 39     int maxson = 0, now;
 40     Size[x] = 1;//先加上自己
 41     for(R i = Head[x]; i ; i = Next[i])
 42     {
 43         now = date[i];
 44         if(now == father[x]) continue;
 45         deep[now] = deep[x] + 1;
 46         dfs1(now);
 47         Size[x] += Size[now];
 48         if(Size[now] > Size[maxson]) maxson = now;
 49     }
 50     son[x] = maxson;
 51 }
 52 
 53 void dfs2(int x, int topx)//get top && id
 54 {
 55     int now;
 56     id[x] = ++cnt;
 57     top[x] = topx;
 58     if(!son[x]) return ;
 59     dfs2(son[x], topx);//继承top
 60     for(R i = Head[x]; i ; i = Next[i])
 61     {
 62         now = date[i];
 63         if(now == father[x] || now == son[x]) continue;//这两个都是不能去的
 64         dfs2(now, now);//新开
 65     }
 66 }
 67 
 68 void build(int x, int ll, int rr)
 69 {
 70     l[x] = ll, r[x] = rr;
 71     if(ll == rr) return ;//...调试没删
 72     int mid = (ll + rr) >> 1;
 73     build(x * 2, ll, mid);
 74     build(x * 2 + 1, mid + 1, rr); 
 75 }
 76 
 77 inline void update(int x)
 78 {
 79     int ll = x * 2, rr = ll + 1;
 80     lazy[ll] = lazy[rr] = lazy[x];
 81     tree[ll] = (r[ll] - l[ll] + 1) * (lazy[x] - 1);//要么全为0,要么全为1
 82     tree[rr] = (r[rr] - l[rr] + 1) * (lazy[x] - 1);//为了方便判断
 83     lazy[x] = 0;//下传标记之后要清0
 84 }//1 表示 0, 2 表示1,所以用的时候要-1
 85 
 86 void search(int x, int ll, int rr)
 87 {
 88     if(lazy[x]) update(x);
 89     if(ll == l[x] && rr == r[x]) 
 90     {
 91         ans -= tree[x];
 92         return ;
 93     }
 94     else
 95     {
 96         int mid = (l[x] + r[x]) >> 1;
 97         if(ll > mid) search(x * 2 + 1, ll, rr);
 98         else if(rr <= mid) search(x * 2, ll, rr);
 99         else
100         {
101             search(x * 2, ll, mid);
102             search(x * 2 + 1, mid + 1, rr);
103         } 
104     }
105 }
106 
107 void change(int x, int ll, int rr)
108 {
109     if(l[x] == ll && r[x] == rr) 
110     {
111         lazy[x] = w;
112         tree[x] = (r[x] - l[x] + 1) * (w - 1); 
113     } 
114     else
115     {
116         int mid = (l[x] + r[x]) >> 1;
117         if(ll > mid) change(x * 2 + 1, ll, rr);
118         else if(rr <= mid) change(x * 2, ll, rr);
119         else
120         {
121             change(x * 2, ll, mid);
122             change(x * 2 + 1, mid + 1, rr);
123         } 
124         tree[x] = tree[x * 2] + tree[x * 2 + 1];//因为是直接修改,而不是加减,所以在这里修改tree[x]的值 
125     }
126 }
127 
128 void install(int x)
129 {
130     ans = deep[x];
131     w = 2;//改为1(这里2代表1)
132     while(x)//father[top[1]] = 0;
133     {
134         search(1, id[top[x]], id[x]);
135         change(1, id[top[x]], id[x]);
136         x = father[top[x]];
137     }
138     printf("%d\n", ans);
139 }
140 
141 void uninstall(int x)
142 {
143     ans = 0;
144     search(1, id[x], id[x] + Size[x] - 1);
145     w = 1;
146     change(1, id[x], id[x] + Size[x] - 1);                                                                                        
147     printf("%d\n", -ans);//因为默认是减,所以直接求的话会是相反数
148 }
149 
150 void work()//读入询问
151 {
152     int a;
153     m = read();
154     //scanf("%d", &m);
155     for(R i = 1; i <= m; i++)
156     {
157         scanf("%s", s + 1);
158     //    printf("%d: ", i);
159     //    printf("%d ", l[7424]);
160         //b = i;//辅助watch
161         a = read() + 1;
162         if(s[1] == 'i') install(a);//安装
163         else uninstall(a);
164     }
165 }
166 
167 int main()
168 {
169 //    freopen("in.in", "r", stdin);
170     pre();
171     dfs1(1);
172     dfs2(1, 1);
173     build(1, 1, n);
174     work();
175 //    fclose(stdin);
176     return 0;
177 }

猜你喜欢

转载自www.cnblogs.com/ww3113306/p/9249781.html