虚树(HNOI2014 世界树)

开坑虚树

2018.3.24这个坑可能需要闲置一段时间qaq

2018.5.17妈妈我也会写这题了QwQ

首先建出虚树,网上模板很多,不再详述(其实就是懒得写)

然后我们发现对于虚树上的一条父子边,显然对应一坨东西。具体来说大概是size[u的v方向第一个儿子] - size[v]

然后先处理出虚树上的点每个点属于哪个关键点,先用儿子更新父亲然后用父亲更新儿子

那么对于父子边上的一坨点,如果父子属于同一个关键点,显然把这一坨东西加上去就好了

如果不属于,令分界点为k,即满足k和k以上的一坨都是父亲节点管的,令d[i]表示i的深度,那么d[v]-d[k]+d2=d[k]-d[u]+d1

d1和d2代表u和v到各自关键点的距离。所以d[k] = 1/2*(d[v] + d[u] + d2 - d1)。当后面这坨(不乘二分之一)是偶数的时候,显然k对应的这一个或者一坨点到两个关键点距离一样,这时候判一下标号大小

然后细节处理好就行了

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<set>
  4 #include<vector>
  5 using namespace std;
  6 int n , qu;
  7 struct gg
  8 {
  9     int num , g;
 10 }p[300005];
 11 int dft = 0;
 12 vector<int> E[300005];
 13 vector<int> E2[300005];
 14 vector<int> s;
 15 set<int> q;
 16 int dep[300005];
 17 bool tag[300005];
 18 int f[300005][20] , dfn[300005] , r[300005] , size[300005] , ans[300005] , gs[300005];
 19 pair<int,int> wh[300005];
 20 int g[300005] , root;
 21 inline int read()
 22 {
 23     char ch = getchar();
 24     int s = 0;
 25     while(!('0' <= ch && ch <= '9')) ch = getchar();
 26     while('0' <= ch && ch <= '9'){
 27         s = s * 10 + ch - '0';
 28         ch = getchar();
 29     }
 30     return s;
 31 }
 32 void dfs(int fa,int u,int d)
 33 {
 34     dfn[u] = ++dft;size[u] = 1;
 35     dep[u] = d;
 36     if(fa)f[u][0] = fa;
 37     else f[u][0] = u;
 38     for(int i = 0;i < E[u].size();i++){
 39         if(E[u][i] != fa) {dfs(u , E[u][i] , d + 1);size[u] += size[E[u][i]];}
 40     }
 41     r[u] = dft;
 42     return;
 43 }
 44 void pre()
 45 {
 46     for(int i = 1;i <= 19;i++){
 47         for(int j = 1;j <= n;j++){
 48             f[j][i] = f[f[j][i - 1]][i - 1];
 49         }
 50     }
 51     return;
 52 }
 53 int query(int u,int v)
 54 {
 55     if(dep[u] < dep[v]) swap(u , v);
 56     for(int i = 19;i >= 0;i--){
 57         if(dep[f[u][i]] >= dep[v]) u = f[u][i];
 58     }
 59     if(u == v) return u;
 60     for(int i = 19;i >= 0;i--){
 61         if(f[u][i] != f[v][i]){
 62             u = f[u][i] , v = f[v][i];
 63         }
 64     }
 65     return f[u][0];
 66 }
 67 bool cmp(gg a,gg b)
 68 {
 69     return a.g < b.g;
 70 }
 71 inline void add(int u,int v){/*printf("ADD %d %d\n",u,v);*/E2[u].push_back(v);E2[v].push_back(u);return;}
 72 void dfs2(int fa,int u)
 73 {
 74     g[u] = size[u];
 75     if(tag[u]) wh[u] = pair<int,int>{u , 0};
 76     for(int i = 0;i < E2[u].size();i++){
 77         if(E2[u][i] != fa) dfs2(u , E2[u][i]);
 78     }
 79     if(wh[fa].first == 0 || wh[fa].second > dep[u] - dep[fa] + wh[u].second){
 80         wh[fa].first = wh[u].first;wh[fa].second = dep[u] - dep[fa] + wh[u].second;
 81     }
 82     else if(wh[fa].second == dep[u] - dep[fa] + wh[u].second && wh[fa].first > wh[u].first) wh[fa].first = wh[u].first;
 83     return;
 84 }
 85 void dfs3(int fa,int u)
 86 {
 87     for(int i = 0;i < E2[u].size();i++){
 88         if(E2[u][i] != fa){
 89             if(wh[E2[u][i]].second > wh[u].second + dep[E2[u][i]] - dep[u]){wh[E2[u][i]].first = wh[u].first;wh[E2[u][i]].second = wh[u].second + dep[E2[u][i]] - dep[u];}
 90             else if(wh[E2[u][i]].second == wh[u].second + dep[E2[u][i]] - dep[u] && wh[E2[u][i]].first > wh[u].first) wh[E2[u][i]].first = wh[u].first;
 91             dfs3(u , E2[u][i]);
 92         }
 93     }
 94     return;
 95 }
 96 int get(int u,int v)
 97 {
 98     for(int i = 19;i >= 0;i--){
 99         if(dep[f[u][i]] > v) u = f[u][i];
100     }
101     return u;
102 }
103 int jump(int u,int k)
104 {
105     int s = 0;
106     while(k){
107         if(k&1) u = f[u][s];
108         k >>= 1;s++;
109     }
110     return u;
111 }
112 void calc(int fa,int u)
113 {
114     ans[wh[u].first]++;g[u]--;
115     for(int i = 0;i < E2[u].size();i++){
116         if(E2[u][i] != fa){
117             int v = E2[u][i];
118             if(wh[u].first == wh[v].first){int t = size[get(v , u)] - size[v];ans[wh[u].first] += t;g[u] -= t;}
119             else if(dep[u] != dep[v] - 1){
120                 int d1 = wh[u].second , d2 = wh[v].second , gq;
121                 int dk = (dep[v] + dep[u] - d1 + d2);
122                 if(dk % 2 == 0 && wh[u].first > wh[v].first) dk -= 2;
123                 int t = jump(v , dep[v] - (dk>>1) - 1);gq = size[t] - size[v];ans[wh[v].first] += gq;g[u] -= gq;
124                 gq = size[get(t , u)] - size[t];ans[wh[u].first] += gq;g[u] -= gq;
125             }
126             calc(u , v);
127             g[u] -= size[v];
128         }
129     }
130     if(g[u]) ans[wh[u].first] += g[u];
131     return;
132 }
133 void solve()
134 {
135     dfs2(0 , root);
136     dfs3(0 , root);
137     ans[wh[root].first] = size[1] - size[root];
138     calc(0 , root);
139     return;
140 }
141 int main()
142 {
143     n = read();
144     for(int i = 1;i < n;i++){
145         int x , y;
146         x = read() , y = read();
147         E[x].push_back(y);
148         E[y].push_back(x);
149     }
150     dfs(0 , 1 , 1);
151     pre();
152     qu = read();
153     while(qu--){
154         int m = read();q.clear();root = 0;
155         for(int i = 1;i <= m;i++){
156             int x = read();tag[x] = 1;
157             p[i].num = x;p[i].g = dfn[x];gs[i] = x;
158             if(dep[x] < dep[root] || root == 0) root = x;
159         }
160         sort(p + 1 , p + m + 1 , cmp);
161         vector<int>::iterator it;
162         for(int i = 1;i <= m;i++){
163             if(!s.size() || r[s[s.size() - 1]] >= p[i].g){s.push_back(p[i].num);q.insert(p[i].num);continue;}
164             int lca = query(p[i].num , s[s.size() - 1]);
165             if(dep[lca] < dep[root]) root = lca;
166             while(s.size() > 1 && dep[s[s.size() - 2]] > dep[lca]){it = s.end();it--;add(*it , s[s.size() - 2]);s.erase(it);}
167             it = s.end();it--;add(*it , lca);s.erase(it);
168             if(q.find(lca) == q.end()){s.push_back(lca);q.insert(lca);}
169             s.push_back(p[i].num);q.insert(p[i].num);
170         }
171         while(s.size() > 1){it = s.end();it--;add(*it , s[s.size() - 2]);s.erase(it);}
172         s.clear();
173         solve();
174         for(int i = 1;i <= m;i++) printf("%d ",ans[gs[i]]);
175         printf("\n");
176         set<int>::iterator it2 = q.begin();
177         while(it2 != q.end()) {E2[*it2].clear();tag[*it2] = ans[*it2] = g[*it2] = 0;wh[*it2] = pair<int,int>{0 , 0};it2++;}
178     }
179     return 0;
180 }
View Code

 

转载于:https://www.cnblogs.com/RDDCCD/p/8622868.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值