SPOJ - QTREE5 Query on a tree V 边分治

题目传送门

题意:给你一棵树, 然后树上的点都有颜色,且原来为黑,现在有2个操作,1 改变某个点的颜色, 2 询问树上的白点到u点的最短距离是多少。

题解:

这里用的还是边分治的方法。

把所有东西都抠出来, 然后每次询问的时候都访问每幅分割图的另外一侧。

代码:

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
  4 #define LL long long
  5 #define ULL unsigned LL
  6 #define fi first
  7 #define se second
  8 #define pb push_back
  9 #define lson l,m,rt<<1
 10 #define rson m+1,r,rt<<1|1
 11 #define lch(x) tr[x].son[0]
 12 #define rch(x) tr[x].son[1]
 13 #define max3(a,b,c) max(a,max(b,c))
 14 #define min3(a,b,c) min(a,min(b,c))
 15 typedef pair<int,int> pll;
 16 const int inf = 0x3f3f3f3f;
 17 const LL INF = 0x3f3f3f3f3f3f3f3f;
 18 const LL mod =  (int)1e9+7;
 19 const int N = 2e5 + 100;
 20 struct Node{
 21     int head[N], to[N<<1], nt[N<<1], ct[N<<1];
 22     int tot;
 23     void init(){
 24         memset(head, -1, sizeof(head));
 25         tot = 0;
 26     }
 27     void add(int u, int v, int cost){
 28         ct[tot] = cost;
 29         to[tot] = v;
 30         nt[tot] = head[u];
 31         head[u] = tot++;
 32     }
 33 }e[2];
 34 int n, m, white[N], cut[N<<1];
 35 void rebuild(int o, int u){
 36     int ff = 0;
 37     for(int i = e[0].head[u]; ~i; i = e[0].nt[i]){
 38         int v = e[0].to[i];
 39         if(o == v) continue;
 40         if(!ff){
 41             e[1].add(u, v, 1);
 42             e[1].add(v, u, 1);
 43             ff = u;
 44         }
 45         else {
 46             ++n;
 47             e[1].add(ff, n, 0); e[1].add(n, ff, 0);
 48             e[1].add(n, v, 1); e[1].add(v, n, 1);
 49             ff = n;
 50         }
 51         rebuild(u, v);
 52     }
 53 }
 54 int sz[N], minval, id;
 55 void get_edge(int o, int u, int num){
 56     sz[u] = 1;
 57     for(int i = e[1].head[u]; ~i; i = e[1].nt[i]){
 58         int v = e[1].to[i];
 59         if(v == o || cut[i>>1]) continue;
 60         get_edge(u, v, num);
 61         sz[u] += sz[v];
 62         int tmp = max(sz[v], num - sz[v]);
 63         if(tmp < minval){
 64             minval = tmp;
 65             id = i;
 66         }
 67     }
 68 }
 69 int k = 0, op;
 70 vector<pll> vc[N];
 71 priority_queue<pll, vector<pll>, greater<pll> > pq[N<<2][2];
 72 int wedge[N<<2];
 73 int mm;
 74 void dfs2(int o, int u, int w){
 75     vc[u].pb(pll(k*op, w));
 76     sz[u] = 1;
 77     for(int i = e[1].head[u]; ~i; i = e[1].nt[i]){
 78         int v = e[1].to[i];
 79         if(v == o || cut[i>>1]) continue;
 80         dfs2(u, v, w + e[1].ct[i]);
 81         sz[u] += sz[v];
 82     }
 83 }
 84 void solve(int u, int num){
 85     if(num <= 1) return ;
 86     minval = inf;
 87     get_edge(0, u, num);
 88     int nid = id;
 89     cut[nid>>1] = 1;
 90     ++k;
 91     op = 1;
 92     dfs2(0, e[1].to[nid], 0);
 93     op = -1;
 94     dfs2(0, e[1].to[nid^1], 0);
 95     wedge[k] = e[1].ct[nid];
 96     solve(e[1].to[nid], sz[e[1].to[nid]]);
 97     solve(e[1].to[nid^1], sz[e[1].to[nid^1]]);
 98 }
 99 void Update(int k){
100     while(!pq[k][0].empty() && !white[pq[k][0].top().se]) pq[k][0].pop();
101     while(!pq[k][1].empty() && !white[pq[k][1].top().se]) pq[k][1].pop();
102 }
103 void setwhite(int u){
104     for(int i = 0; i < vc[u].size(); i++){
105         int k = vc[u][i].fi, w = vc[u][i].se;
106         if(k < 0) pq[-k][0].push(pll(w,u));
107         else pq[k][1].push(pll(w,u));
108         Update(abs(k));
109     }
110 }
111 void setblack(int u){
112     for(int i = 0; i < vc[u].size(); i++){
113         int k = vc[u][i].fi;
114         Update(abs(k));
115     }
116 }
117 int Find(int u){
118     int ret = inf;
119     for(int i = 0; i < vc[u].size(); i++){
120         int k = vc[u][i].fi, w = vc[u][i].se;
121         if(k < 0 && !pq[-k][1].empty())
122                 ret = min(ret, w+wedge[-k]+pq[-k][1].top().fi);
123         if(k > 0 && !pq[k][0].empty())
124             ret = min(ret, w+wedge[k]+pq[k][0].top().fi);
125     }
126     return ret;
127 }
128 int main(){
129     e[0].init(); e[1].init();
130     scanf("%d", &n);
131     int u, v;
132     for(int i = 1; i < n; i++){
133         scanf("%d%d", &u, &v);
134         e[0].add(u, v, 1); e[0].add(v, u, 1);
135     }
136     memset(white, 0, sizeof(white));
137     rebuild(0, 1);
138     solve(1, n);
139     int num = 0, op;
140     scanf("%d", &m);
141     while(m--){
142         scanf("%d%d", &op, &v);
143         if(op == 0){
144             white[v] ^= 1;
145             if(white[v]){
146                 setwhite(v);
147                 num++;
148             }
149             else {
150                 setblack(v);
151                 num--;
152             }
153         }
154         else {
155             if(num == 0) puts("-1");
156             else if(white[v]) puts("0");
157             else {
158                 printf("%d\n", Find(v));
159             }
160         }
161     }
162     return 0;
163 }
View Code

 

转载于:https://www.cnblogs.com/MingSD/p/9916567.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值