Codeforces Round #329 (Div. 2) D. Happy Tree Party(LCA+并查集)

题目链接

题意:就是给你一颗这样的树,用一个$y$来除以两点之间每条边的权值,比如$3->7$,问最后的y的是多少,修改操作是把权值变成更小的。

这个$(y<=10^{18})$除的权值如果是$>=2$,那么最多除60几次就变成0了,问题关键是路径上会有好多1存在,这时候我们可以用并查集把他们并到一块,这样就能跳着查了。

具体查法:

从$u$到$LCA(u,v)$,路径上除一遍。

从$v$到$LCA(u,v)$,路径上除一遍。

修改操作如果变成1,就与前面的点合并。

 

  1 #include <iostream>
  2 #include <algorithm>
  3 #include <cstdio>
  4 using namespace std;
  5 
  6 typedef long long ll;
  7 const int maxn = 2e5 + 10;
  8 ///加边
  9 int cnt = 0, h[maxn];
 10 struct edge
 11 {
 12     int to, pre;
 13     ll v;
 14 } e[maxn << 1];
 15 void add(int from, int to, ll v)
 16 {
 17     cnt++;
 18     e[cnt].pre = h[from]; ///5-->3-->1-->0
 19     e[cnt].to = to;
 20     e[cnt].v = v;
 21     h[from] = cnt;
 22 }
 23 ///LCA
 24 int dist[maxn];
 25 int dep[maxn];
 26 int anc[maxn][33]; ///2分的父亲节点
 27 ll len[maxn];
 28 void dfs(int u, int fa)
 29 {
 30     for(int i = h[u]; i; i = e[i].pre)
 31     {
 32         int v = e[i].to;
 33         if(v == fa) continue;
 34         dist[v] = dist[u] + e[i].v;
 35         dep[v] = dep[u] + 1;
 36         anc[v][0] = u;
 37         len[v] = e[i].v;
 38         dfs(v, u);
 39     }
 40 }
 41 void LCA_init(int n)
 42 {
 43     for(int j = 1; (1 << j) < n; j++)
 44         for(int i = 1; i <= n; i++) if(anc[i][j-1])
 45         anc[i][j] = anc[anc[i][j-1]][j-1];
 46 }
 47 int LCA(int u, int v)
 48 {
 49     int log;
 50     if(dep[u] < dep[v]) swap(u, v);
 51     for(log = 0; (1 << log) < dep[u]; log++);
 52     for(int i = log; i >= 0; i--)
 53         if(dep[u] - (1 << i) >= dep[v]) u = anc[u][i];
 54     if(u == v) return u;
 55     for(int i = log; i >= 0; i--)
 56         if(anc[u][i] && anc[u][i] != anc[v][i])
 57             u = anc[u][i], v = anc[v][i];
 58     return anc[u][0];
 59 }
 60 int fa[maxn];
 61 int Find(int x)
 62 {
 63     if(x == fa[x]) return x;
 64     return fa[x] = Find(fa[x]);
 65 }
 66 int main()
 67 {
 68     int n, m; scanf("%d %d", &n, &m);
 69     cnt = 1;
 70     for(int i = 1; i <= n; i++) h[i] = 0;
 71     for(int i = 1; i <= n - 1; i++)
 72     {
 73         int u, v;
 74         ll w; scanf("%d %d %lld", &u, &v, &w);
 75         add(u, v, w), add(v, u, w);
 76     }
 77     ///LCA初始化
 78     dfs(1, 0);
 79     LCA_init(n);
 80     ///并查集初始化
 81     for(int i = 1; i <= n; i++) fa[i] = i;
 82     while(m--)
 83     {
 84         int op, a, b, p;
 85         ll c, y;
 86         scanf("%d", &op);
 87         if(op == 1)
 88         {
 89            scanf("%d %d %lld", &a, &b, &y);
 90            int fp = LCA(a, b);
 91            a = Find(a);
 92            while(dep[a] > dep[fp] && y > 0LL)
 93            {
 94                if(len[a] == 1LL)
 95                {
 96                    fa[a] = anc[a][0];
 97                    a = Find(a);
 98                }
 99                else
100                {
101                    y /= len[a];
102                    a = Find(anc[a][0]);
103                }
104            }
105            b = Find(b);
106            while(dep[b] > dep[fp] && y > 0LL)
107            {
108                if(len[b] == 1LL)
109                {
110                    fa[b] = anc[b][0];
111                    b = Find(b);
112                }
113                else
114                {
115                    y /= len[b];
116                    b = Find(anc[b][0]);
117                }
118            }
119            printf("%lld\n", y);
120         }
121         else
122         {
123             scanf("%d %lld", &p, &c);
124             int u = e[p * 2].to, v = e[(p * 2) ^ 1].to;
125             if(u == anc[v][0])
126             {
127                 len[v] = c;
128                 if(c == 1LL)
129                 {
130                     fa[v] = u;
131                 }
132             }
133             else
134             {
135                 len[u] = c;
136                 if(c == 1LL)
137                 {
138                     fa[u] = v;
139                 }
140             }
141         }
142     }
143     return 0;
144 }

 

posted @ 2018-09-20 21:16  汪汪鱼  阅读(224)  评论(0编辑  收藏  举报