LCA统计
读入挂
- inline void read(int &v)
- {
- v = ;
- char c = ;
- int p = ;
- while (c < '' || c > '')
- {
- if (c == '-')
- {
- p = -;
- }
- c = getchar();
- }
- while (c >= '' && c <= '')
- {
- v = (v << ) + (v << ) + c - '';
- c = getchar();
- }
- v *= p;
- }
基本模板
离线:
- /*Huyyt*/
- #include<bits/stdc++.h>
- #define mem(a,b) memset(a,b,sizeof(a))
- #define pb push_back
- using namespace std;
- typedef long long ll;
- typedef unsigned long long ull;
- using namespace std;
- const int MAXN = 1e5 + , MAXM = 1e5 + ;
- const int MAXQ = 1e5 + ;
- int to[MAXM << ], nxt[MAXM << ], Head[MAXN], ed = ;
- int value[MAXM << ];
- inline void addedge(int u, int v, int val)
- {
- to[++ed] = v;
- nxt[ed] = Head[u];
- value[ed] = val;
- Head[u] = ed;
- }
- int fa[MAXN], d[MAXN], vis[MAXN], LCA[MAXQ], ans[MAXQ];
- vector<int> query[MAXQ], query_id[MAXQ];
- void add_query(int x, int y, int id)
- {
- query[x].push_back(y), query_id[x].push_back(id);
- query[y].push_back(x), query_id[y].push_back(id);
- }
- int get(int x)
- {
- if (x == fa[x])
- {
- return x;
- }
- return fa[x] = get(fa[x]);
- }
- void tarjan(int x)
- {
- vis[x] = ;
- for (int v, i = Head[x]; i; i = nxt[i])
- {
- v = to[i];
- if (vis[v])
- {
- continue;
- }
- d[v] = d[x] + value[i];
- tarjan(v);
- fa[v] = x;
- }
- for (int i = ; i < query[x].size(); i++)
- {
- int v = query[x][i], id = query_id[x][i];
- if (vis[v] == )
- {
- LCA[id] = get(v);
- ans[id] = min(ans[id], d[x] + d[v] - * d[LCA[id]]);
- }
- }
- vis[x] = ;
- }
- int n, m;
- int u, v, z;
- int main()
- {
- int T;
- scanf("%d", &T);
- while (T--)
- {
- scanf("%d %d", &n, &m);
- for (int i = ; i <= n; i++)
- {
- vis[i] = Head[i] = , fa[i] = i;
- query[i].clear(), query_id[i].clear();
- }
- ed = ;
- for (int i = ; i < n; i++)
- {
- scanf("%d %d %d", &u, &v, &z);
- addedge(u, v, z), addedge(v, u, z);
- }
- for (int i = ; i <= m; i++)
- {
- scanf("%d %d", &u, &v);
- if (u == v)
- {
- ans[i] = ;
- LCA[i] = u;
- }
- else
- {
- add_query(u, v, i);
- ans[i] = << ;
- }
- }
- tarjan();
- for (int i = ; i <= m; i++)
- {
- printf("%d\n", ans[i]);
- }
- }
- return ;
- }
//HDU2586
倍增:
- for (int j=;j<=;j++){
- for (int i=;i<=n;i++) f[i][j]=f[f[i][j-]][j-],
- minn[i][j]=min(minn[i][j-],minn[f[i][j-]][j-]);
- }
- int lca(int x,int y){
- if (dep[x]<dep[y]) swap(x,y);
- int tmp=dep[x]-dep[y];
- for (int i=;i<=;i++){
- if (tmp&(<<i)) x=f[x][i];
- }
- if (x==y) return x;
- for (int i=;i>=;i--){
- if (f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
- }
- return f[x][];
- }
- int dist(int x,int y){
- if (dep[x]<dep[y]) swap(x,y);
- int tmp=dep[x]-dep[y],ret=1e9;
- for (int i=;i<=;i++){
- if (tmp&(<<i)) ret=min(ret,minn[x][i]),x=f[x][i];
- }
- return ret;
- }
HDU 2586 单树带权LCA
在线:
①倍增
- /* Huyyt */
- #include <bits/stdc++.h>
- using namespace std;
- const int maxn = ; //点的最大值
- const int maxl = ; //深度的最大值
- typedef struct
- {
- int from, to, w;
- } edge; //这个结构体用来存储边
- vector<edge> edges;
- vector<int> G[maxn];
- //保存边的数组
- int grand[maxn][maxl]; //x向上跳2^i次方的节点,x到他上面祖先2^i次方的距离
- int gw[maxn][maxl]; //维护距离的数组
- int depth[maxn];//深度
- int root;
- int n, m;
- int N; //N的意思是最多能跳几层
- void addedge(int x, int y, int w) //把边保存起来的函数
- {
- edge a = {x, y, w}, b = {y, x, w};
- edges.push_back(a);
- edges.push_back(b);
- G[x].push_back(edges.size() - );
- G[y].push_back(edges.size() - );
- }
- void dfs(int x)//dfs建图
- {
- for (int i = ; i <= N; i++) //第一个几点就全部都是0,第二个节点就有变化了,不理解的话建议复制代码输出下这些数组
- {
- grand[x][i] = grand[grand[x][i - ]][i - ]; //倍增 2^i=2^(i-1)+2^(i-1)
- gw[x][i] = gw[x][i - ] + gw[grand[x][i - ]][i - ]; //维护一个距离数组
- // if(grand[x][i]==0) break;
- }
- for (int i = ; i < G[x].size(); i++)
- {
- edge e = edges[G[x][i]];
- if (e.to != grand[x][]) //这里我们保存的是双向边所以与他相连的边不是他父亲就是他儿子父亲的话就不能执行,不然就死循环了。
- {
- depth[e.to] = depth[x] + ; //他儿子的深度等于他爸爸的加1
- grand[e.to][] = x; //与x相连那个节点的父亲等于x
- gw[e.to][] = e.w; //与x相连那个节点的距离等于这条边的距离
- dfs(e.to);//深搜往下面建
- }
- }
- }
- void Init()
- {
- //n为节点个数
- N = floor(log(n + 0.0) / log(2.0));//最多能跳的2^i祖先
- depth[root] = ; //根结点的祖先不存在,用-1表示
- memset(grand, , sizeof(grand));
- memset(gw, , sizeof(gw));
- dfs(root);//以1为根节点建树
- }
- int lca(int a, int b)
- {
- if (depth[a] > depth[b])
- {
- swap(a, b); //保证a在b上面,便于计算
- }
- int ans = ;
- for (int i = N; i >= ; i--) //类似于二进制拆分,从大到小尝试
- {
- if (depth[a] < depth[b] && depth[grand[b][i]] >= depth[a]) //a在b下面且b向上跳后不会到a上面
- {
- ans += gw[b][i], b = grand[b][i]; //先把深度较大的b往上跳
- }
- }
- if (a == b)
- {
- return ans;
- }
- for (int j = N; j >= ; j--) //在同一高度了,他们一起向上跳,跳他们不相同节点,当全都跳完之后grand【a】【0】就是lca,上面有解释哈。
- {
- if (grand[a][j] != grand[b][j])
- {
- ans += gw[a][j];
- ans += gw[b][j];
- a = grand[a][j];
- b = grand[b][j];
- }
- }
- if (a != b) //a等于b的情况就是上面土色字体的那种情况
- {
- ans += gw[a][], ans += gw[b][];
- }
- return ans;
- }
- int main()
- {
- depth[] = -;
- int t ;
- scanf("%d", &t);
- while (t--)
- {
- root = ;
- scanf("%d%d", &n, &m);
- for (int i = ; i < n; i++)
- {
- int x, y, w;
- scanf("%d%d%d", &x, &y, &w);
- addedge(x, y, w);
- }
- Init();
- for (int i = ; i <= m; i++)
- {
- int x, y;
- scanf("%d%d", &x, &y);
- printf("%d\n", lca(x, y));
- }
- }
- }
离线:
②Tarjan
- /*Huyyt*/
- #include<bits/stdc++.h>
- using namespace std;
- const int MAXN = ;//点的最大值
- const int MAXQ = ;//查询数的最大值
- inline int readint()
- {
- char c = getchar();
- int ans = ;
- while (c < '' || c > '')
- {
- c = getchar();
- }
- while (c >= '' && c <= '')
- {
- ans = ans * + c - '', c = getchar();
- }
- return ans;
- }
- //并查集部分
- int F[MAXN];//需要初始化为-1
- int find(int x)
- {
- if (F[x] == -)
- {
- return x;
- }
- return F[x] = find(F[x]);
- }
- void bing(int u, int v)
- {
- int t1 = find(u);
- int t2 = find(v);
- if (t1 != t2)
- {
- F[t1] = t2;
- }
- }
- bool vis[MAXN];//访问标记
- int ancestor[MAXN];//祖先
- int distence[MAXN];
- struct Edge
- {
- int to, next, dis;
- } edge[MAXN * ];
- int head[MAXN], tot;
- void addedge(int u, int v, int d)
- {
- edge[tot].to = v;
- edge[tot].dis = d;
- edge[tot].next = head[u];
- head[u] = tot++;
- }
- struct Query
- {
- int q, next;
- int index;//查询编号
- } query[MAXQ * ];
- int answer[MAXQ];//存储最后的查询结果,下标0~Q-1
- int h[MAXQ];
- int tt;
- int Q;
- void add_query(int u, int v, int index)
- {
- query[tt].q = v;
- query[tt].next = h[u];
- query[tt].index = index;
- h[u] = tt++;
- query[tt].q = u;
- query[tt].next = h[v];
- query[tt].index = index;
- h[v] = tt++;
- }
- void init()
- {
- tot = ;
- memset(head, -, sizeof(head));
- memset(distence, , sizeof(distence));
- tt = ;
- memset(h, -, sizeof(h));
- memset(vis, false, sizeof(vis));
- memset(F, -, sizeof(F));
- memset(ancestor, , sizeof(ancestor));
- }
- void getdistence(int x, int pre)
- {
- for (int i = head[x]; i != -; i = edge[i].next)
- {
- int v = edge[i].to;
- if (v == pre)
- {
- continue;
- }
- distence[v] = distence[x] + edge[i].dis;
- getdistence(v, x);
- }
- }
- void LCA(int u)
- {
- ancestor[u] = u;
- vis[u] = true;
- for (int i = head[u]; i != -; i = edge[i].next)
- {
- int v = edge[i].to;
- if (vis[v])
- {
- continue;
- }
- LCA(v);
- bing(u, v);
- ancestor[find(u)] = u;
- }
- for (int i = h[u]; i != -; i = query[i].next)
- {
- int v = query[i].q;
- if (vis[v])
- {
- answer[query[i].index] = distence[v] + distence[u] - * distence[ancestor[find(v)]];
- }
- }
- }
- bool flag[MAXN];
- int main()
- {
- int T;
- T = readint();
- int n;
- int u, v, k;
- int len;
- while (T--)
- {
- n = readint();
- Q = readint();
- init();
- memset(flag, false, sizeof(flag));
- for (int i = ; i < n; i++)
- {
- u = readint();
- v = readint();
- len = readint();
- flag[v] = true;
- addedge(u, v, len);
- addedge(v, u, len);
- }
- for (int i = ; i < Q; i++)
- {
- u = readint();
- v = readint();
- add_query(u, v, i);
- }
- int root;
- for (int i = ; i <= n; i++)
- if (!flag[i])
- {
- root = i;
- break;
- }
- distence[root] = ;
- getdistence(root, -);
- LCA(root);
- for (int i = ; i < Q; i++)
- {
- cout << answer[i] << endl;
- }
- }
- return ;
- }
hihocoder 1062 多树不带权LCA
离线:
①Tarjan
- #include<bits/stdc++.h>
- using namespace std;
- const int MAXN = ;
- const int MAXQ = ;//查询数的最大值
- inline int readint()
- {
- char c = getchar();
- int ans = ;
- while (c < '' || c > '')
- {
- c = getchar();
- }
- while (c >= '' && c <= '')
- {
- ans = ans * + c - '', c = getchar();
- }
- return ans;
- }
- //并查集部分
- int F[MAXN];//需要初始化为-1
- int find(int x)
- {
- if (F[x] == -)
- {
- return x;
- }
- return F[x] = find(F[x]);
- }
- void bing(int u, int v)
- {
- int t1 = find(u);
- int t2 = find(v);
- if (t1 != t2)
- {
- F[t1] = t2;
- }
- }
- //************************
- bool vis[MAXN];//访问标记
- int ancestor[MAXN];//祖先
- struct Edge
- {
- int to, next;
- } edge[MAXN * ];
- int head[MAXN], tot;
- void addedge(int u, int v)
- {
- edge[tot].to = v;
- edge[tot].next = head[u];
- head[u] = tot++;
- }
- struct Query
- {
- int q, next;
- int index;//查询编号
- } query[MAXQ * ];
- int answer[MAXQ];//存储最后的查询结果,下标0~Q-1
- int finalfather[MAXN];
- void getfather(int x, int pre, int aim)
- {
- finalfather[x] = aim;
- for (int i = head[x]; i != -; i = edge[i].next)
- {
- int v = edge[i].to;
- if (v == pre)
- {
- continue;
- }
- getfather(v, x, aim);
- }
- }
- int h[MAXQ];
- int tt;
- int Q;
- void add_query(int u, int v, int index)
- {
- query[tt].q = v;
- query[tt].next = h[u];
- query[tt].index = index;
- h[u] = tt++;
- query[tt].q = u;
- query[tt].next = h[v];
- query[tt].index = index;
- h[v] = tt++;
- }
- void init()
- {
- tot = ;
- memset(head, -, sizeof(head));
- tt = ;
- memset(h, -, sizeof(h));
- memset(vis, false, sizeof(vis));
- memset(F, -, sizeof(F));
- memset(ancestor, , sizeof(ancestor));
- }
- void LCA(int u)
- {
- ancestor[u] = u;
- vis[u] = true;
- for (int i = head[u]; i != -; i = edge[i].next)
- {
- int v = edge[i].to;
- if (vis[v])
- {
- continue;
- }
- LCA(v);
- bing(u, v);
- ancestor[find(u)] = u;
- }
- for (int i = h[u]; i != -; i = query[i].next)
- {
- int v = query[i].q;
- if (vis[v])
- {
- //cout << " " << u << " " << v << " " << find(u) << " " << find(v)<<endl;
- if (finalfather[v] != finalfather[u])
- {
- answer[query[i].index] = -;
- }
- answer[query[i].index] = ancestor[find(v)];
- }
- }
- }
- map<string, int> mp;
- map<int, string> mpback;
- int Qflag[MAXQ];
- int pop = ;
- string anser[MAXN];
- string from, to;
- void getnum(string x)
- {
- if (mp[x])
- {
- return ;
- }
- mp[x] = ++pop;
- mpback[pop] = x;
- return ;
- }
- bool flag[MAXN];
- int main()
- {
- int n;
- int u, v, k;
- while (scanf("%d", &n) == )
- {
- for (int i = ; i < MAXN; i++)
- {
- anser[i] = "";
- }
- init();
- memset(flag, false, sizeof(flag));
- for (int i = ; i <= n; i++)
- {
- cin >> from >> to;
- getnum(from);
- getnum(to);
- //cout << mp[from] << " " << mp[to] << endl;
- flag[mp[to]] = true;
- addedge(mp[from], mp[to]);
- addedge(mp[to], mp[from]);
- }
- Q = readint();
- for (int i = ; i < Q; i++)
- {
- // u = readint();
- // v = readint();
- // add_query(u, v, i);
- cin >> from >> to;
- if (from == to)
- {
- anser[i] = from;
- }
- else
- {
- if (mp.find(from) == mp.end() || mp.find(to) == mp.end())
- {
- anser[i] = "-1";
- }
- else
- {
- add_query(mp[from], mp[to], i);
- }
- }
- }
- int root;
- for (int i = ; i <= pop; i++)
- {
- if (!flag[i])
- {
- getfather(i, -, i);
- }
- }
- for (int i = ; i <= pop; i++)
- if (!flag[i])
- {
- root = i;
- LCA(root);
- }
- for (int i = ; i < Q; i++)
- {
- if (anser[i] != "")
- {
- cout << anser[i] << endl;
- }
- else
- {
- if (answer[i] == -)
- {
- cout << - << endl;
- }
- else
- {
- cout << mpback[answer[i]] << endl;
- }
- }
- }
- }
- return ;
- }
在线:
①倍增
- /* Huyyt */
- #include <bits/stdc++.h>
- using namespace std;
- const int maxn = ; //点的最大值
- const int maxl = ; //深度的最大值
- typedef struct
- {
- int from, to, w;
- } edge; //这个结构体用来存储边
- vector<edge> edges;
- vector<int> G[maxn];
- //保存边的数组
- int grand[maxn][maxl]; //x向上跳2^i次方的节点,x到他上面祖先2^i次方的距离
- int gw[maxn][maxl]; //维护距离的数组
- //int gwmax[maxn][maxl]; //维护边权最大值的数组
- int depth[maxn];//深度
- int root;
- int n, m;
- int N; //N的意思是最多能跳几层
- map<string, int> mp;
- map<int, string> mpback;
- int pop = ;
- string from, to;
- void addedge(int x, int y, int w) //把边保存起来的函数
- {
- edge a = {x, y, w}, b = {y, x, w};
- edges.push_back(a);
- edges.push_back(b);
- G[x].push_back(edges.size() - );
- G[y].push_back(edges.size() - );
- }
- void dfs(int x)//dfs建图
- {
- for (int i = ; i <= N; i++) //第一个几点就全部都是0,第二个节点就有变化了,不理解的话建议复制代码输出下这些数组
- {
- grand[x][i] = grand[grand[x][i - ]][i - ]; //倍增 2^i=2^(i-1)+2^(i-1)
- gw[x][i] = gw[x][i - ] + gw[grand[x][i - ]][i - ]; //维护一个距离数组
- //gwmax[x][i]=max(gwmax[x][i-1],gw[grand[x][i-1]][i-1]);
- // if(grand[x][i]==0) break;
- }
- for (int i = ; i < G[x].size(); i++)
- {
- edge e = edges[G[x][i]];
- if (e.to != grand[x][]) //这里我们保存的是双向边所以与他相连的边不是他父亲就是他儿子父亲的话就不能执行,不然就死循环了。
- {
- depth[e.to] = depth[x] + ; //他儿子的深度等于他爸爸的加1
- grand[e.to][] = x; //与x相连那个节点的父亲等于x
- gw[e.to][] = e.w; //与x相连那个节点的距离等于这条边的距离
- //gwmax[e.to][0]=e.w;
- dfs(e.to);//深搜往下面建
- }
- }
- }
- void Init()
- {
- //n为节点个数
- N = floor(log(maxn + 0.0) / log(2.0));//最多能跳的2^i祖先
- depth[root] = ; //根结点的祖先不存在,用-1表示
- depth[] = -;
- memset(grand, , sizeof(grand));
- //memset(gw, 0, sizeof(gw));
- dfs(root);//以根节点建树
- }
- int lca(int a, int b)
- {
- if (depth[a] > depth[b])
- {
- swap(a, b); //保证a在b上面,便于计算
- }
- int ans = ;
- for (int i = N; i >= ; i--) //类似于二进制拆分,从大到小尝试
- {
- if (depth[a] < depth[b] && depth[grand[b][i]] >= depth[a]) //a在b下面且b向上跳后不会到a上面
- {
- ans += gw[b][i], b = grand[b][i]; //先把深度较大的b往上跳
- }
- }
- if (a == b)
- {
- return a;
- }
- for (int j = N; j >= ; j--) //在同一高度了,他们一起向上跳,跳他们不相同节点,当全都跳完之后grand【a】【0】就是lca,上面有解释哈。
- {
- if (grand[a][j] != grand[b][j])
- {
- ans += gw[a][j];
- ans += gw[b][j];
- a = grand[a][j];
- b = grand[b][j];
- }
- }
- if (a != b) //a等于b的情况就是上面土色字体的那种情况
- {
- ans += gw[a][], ans += gw[b][];
- }
- if (grand[a][] == && grand[b][] == && a != b)
- {
- return -;
- }
- return grand[a][];
- }
- void getnum(string x)
- {
- if (mp[x])
- {
- return ;
- }
- mp[x] = ++pop;
- mpback[pop] = x;
- return ;
- }
- int in[maxn];
- int main()
- {
- N = floor(log(maxn + 0.0) / log(2.0));
- depth[] = -;
- cin >> n;
- for (int i = ; i <= n; i++)
- {
- cin >> from >> to;
- getnum(from);
- getnum(to);
- //cout << mp[from] << " " << mp[to] << endl;
- addedge(mp[from], mp[to], );
- in[mp[to]]++;
- }
- for (int i = ; i <= pop; i++)
- {
- if (in[i] == )
- {
- root = i;
- dfs(root);
- }
- }
- cin >> m;
- for (int i = ; i <= m; i++)
- {
- cin >> from >> to;
- if (from == to)
- {
- cout << from << endl;
- }
- else
- {
- if (mp.find(from) == mp.end() || mp.find(to) == mp.end())
- {
- cout << - << endl;
- }
- else
- {
- int aim = lca(mp[from], mp[to]);
- if (aim == -)
- {
- cout << - << endl;
- }
- else
- {
- cout << mpback[aim] << endl;
- }
- }
- }
- }
- }
hihocoder 1067 单树不带权LCA
离线:
①Tarjan
- #include<bits/stdc++.h>
- using namespace std;
- const int MAXN = ;
- const int MAXQ = ;//查询数的最大值
- inline int readint()
- {
- char c = getchar();
- int ans = ;
- while (c < '' || c > '')
- {
- c = getchar();
- }
- while (c >= '' && c <= '')
- {
- ans = ans * + c - '', c = getchar();
- }
- return ans;
- }
- //并查集部分
- int F[MAXN];//需要初始化为-1
- int find(int x)
- {
- if (F[x] == -)
- {
- return x;
- }
- return F[x] = find(F[x]);
- }
- void bing(int u, int v)
- {
- int t1 = find(u);
- int t2 = find(v);
- if (t1 != t2)
- {
- F[t1] = t2;
- }
- }
- //************************
- bool vis[MAXN];//访问标记
- int ancestor[MAXN];//祖先
- struct Edge
- {
- int to, next;
- } edge[MAXN * ];
- int head[MAXN], tot;
- void addedge(int u, int v)
- {
- edge[tot].to = v;
- edge[tot].next = head[u];
- head[u] = tot++;
- }
- struct Query
- {
- int q, next;
- int index;//查询编号
- } query[MAXQ * ];
- int answer[MAXQ];//存储最后的查询结果,下标0~Q-1
- int h[MAXQ];
- int tt;
- int Q;
- void add_query(int u, int v, int index)
- {
- query[tt].q = v;
- query[tt].next = h[u];
- query[tt].index = index;
- h[u] = tt++;
- query[tt].q = u;
- query[tt].next = h[v];
- query[tt].index = index;
- h[v] = tt++;
- }
- void init()
- {
- tot = ;
- memset(head, -, sizeof(head));
- tt = ;
- memset(h, -, sizeof(h));
- memset(vis, false, sizeof(vis));
- memset(F, -, sizeof(F));
- memset(ancestor, , sizeof(ancestor));
- }
- void LCA(int u)
- {
- ancestor[u] = u;
- vis[u] = true;
- for (int i = head[u]; i != -; i = edge[i].next)
- {
- int v = edge[i].to;
- if (vis[v])
- {
- continue;
- }
- LCA(v);
- bing(u, v);
- ancestor[find(u)] = u;
- }
- for (int i = h[u]; i != -; i = query[i].next)
- {
- int v = query[i].q;
- if (vis[v])
- {
- answer[query[i].index] = ancestor[find(v)];
- }
- }
- }
- map<string, int> mp;
- map<int, string> mpback;
- int pop = ;
- string from, to;
- void getnum(string x)
- {
- if (mp[x])
- {
- return ;
- }
- mp[x] = ++pop;
- mpback[pop] = x;
- return ;
- }
- bool flag[MAXN];
- int Count_num[MAXN];
- int main()
- {
- //freopen("in.txt","r",stdin);
- //freopen("out.txt","w",stdout);
- int n;
- int u, v, k;
- while (scanf("%d", &n) == )
- {
- init();
- memset(flag, false, sizeof(flag));
- for (int i = ; i <= n; i++)
- {
- cin >> from >> to;
- getnum(from);
- getnum(to);
- flag[mp[to]]=true;
- addedge(mp[from],mp[to]);
- addedge(mp[to],mp[from]);
- }
- Q = readint();
- for (int i = ; i < Q; i++)
- {
- cin >> from >> to;
- add_query(mp[from],mp[to], i);
- }
- int root;
- for (int i = ; i <= n; i++)
- if (!flag[i])
- {
- root = i;
- break;
- }
- LCA(root);
- memset(Count_num, , sizeof(Count_num));
- for (int i = ; i < Q; i++)
- {
- cout<<mpback[answer[i]]<<endl;
- }
- }
- return ;
- }
在线:
①倍增
- /* Huyyt */
- #include <bits/stdc++.h>
- using namespace std;
- const int maxn = ; //点的最大值
- const int maxl = ; //深度的最大值
- typedef struct
- {
- int from, to, w;
- } edge; //这个结构体用来存储边
- vector<edge> edges;
- vector<int> G[maxn];
- //保存边的数组
- int grand[maxn][maxl]; //x向上跳2^i次方的节点,x到他上面祖先2^i次方的距离
- int gw[maxn][maxl]; //维护距离的数组
- //int gwmax[maxn][maxl]; //维护边权最大值的数组
- int depth[maxn];//深度
- int root;
- int n, m;
- int N; //N的意思是最多能跳几层
- map<string, int> mp;
- map<int, string> mpback;
- int pop = ;
- string from, to;
- void addedge(int x, int y, int w) //把边保存起来的函数
- {
- edge a = {x, y, w}, b = {y, x, w};
- edges.push_back(a);
- edges.push_back(b);
- G[x].push_back(edges.size() - );
- G[y].push_back(edges.size() - );
- }
- void dfs(int x)//dfs建图
- {
- for (int i = ; i <= N; i++) //第一个几点就全部都是0,第二个节点就有变化了,不理解的话建议复制代码输出下这些数组
- {
- grand[x][i] = grand[grand[x][i - ]][i - ]; //倍增 2^i=2^(i-1)+2^(i-1)
- gw[x][i] = gw[x][i - ] + gw[grand[x][i - ]][i - ]; //维护一个距离数组
- //gwmax[x][i]=max(gwmax[x][i-1],gw[grand[x][i-1]][i-1]);
- // if(grand[x][i]==0) break;
- }
- for (int i = ; i < G[x].size(); i++)
- {
- edge e = edges[G[x][i]];
- if (e.to != grand[x][]) //这里我们保存的是双向边所以与他相连的边不是他父亲就是他儿子父亲的话就不能执行,不然就死循环了。
- {
- depth[e.to] = depth[x] + ; //他儿子的深度等于他爸爸的加1
- grand[e.to][] = x; //与x相连那个节点的父亲等于x
- gw[e.to][] = e.w; //与x相连那个节点的距离等于这条边的距离
- //gwmax[e.to][0]=e.w;
- dfs(e.to);//深搜往下面建
- }
- }
- }
- void Init()
- {
- //n为节点个数
- N = floor(log(pop + 0.0) / log(2.0));//最多能跳的2^i祖先
- depth[root] = ; //根结点的祖先不存在,用-1表示
- depth[] = -;
- memset(grand, , sizeof(grand));
- memset(gw, , sizeof(gw));
- dfs(root);//以根节点建树
- }
- int lca(int a, int b)
- {
- if (depth[a] > depth[b])
- {
- swap(a, b); //保证a在b上面,便于计算
- }
- int ans = ;
- for (int i = N; i >= ; i--) //类似于二进制拆分,从大到小尝试
- {
- if (depth[a] < depth[b] && depth[grand[b][i]] >= depth[a]) //a在b下面且b向上跳后不会到a上面
- {
- ans += gw[b][i], b = grand[b][i]; //先把深度较大的b往上跳
- }
- }
- if (a == b)
- {
- return a;
- }
- for (int j = N; j >= ; j--) //在同一高度了,他们一起向上跳,跳他们不相同节点,当全都跳完之后grand【a】【0】就是lca,上面有解释哈。
- {
- if (grand[a][j] != grand[b][j])
- {
- ans += gw[a][j];
- ans += gw[b][j];
- a = grand[a][j];
- b = grand[b][j];
- }
- }
- if (a != b) //a等于b的情况就是上面土色字体的那种情况
- {
- ans += gw[a][], ans += gw[b][];
- }
- return grand[a][];
- }
- void getnum(string x)
- {
- if (mp[x])
- {
- return ;
- }
- mp[x] = ++pop;
- mpback[pop] = x;
- return ;
- }
- int main()
- {
- root = ;
- cin >> n;
- for (int i = ; i <= n; i++)
- {
- cin >> from >> to;
- getnum(from);
- getnum(to);
- //cout << mp[from] << " " << mp[to] << endl;
- addedge(mp[from], mp[to], );
- }
- Init();
- cin >> m;
- for (int i = ; i <= m; i++)
- {
- cin >> from >> to;
- //getnum(from), getnum(to);
- cout << mpback[lca(mp[from], mp[to])] << endl;
- }
- }
hihocoder 1069 在线单树不带权LCA
①倍增
- /* Huyyt */
- #include <bits/stdc++.h>
- using namespace std;
- const int maxn = ; //点的最大值
- const int maxl = ; //深度的最大值
- typedef struct
- {
- int from, to, w;
- } edge; //这个结构体用来存储边
- vector<edge> edges;
- vector<int> G[maxn];
- //保存边的数组
- int grand[maxn][maxl]; //x向上跳2^i次方的节点,x到他上面祖先2^i次方的距离
- int gw[maxn][maxl]; //维护距离的数组
- //int gwmax[maxn][maxl]; //维护边权最大值的数组
- int depth[maxn];//深度
- int root;
- int n, m;
- int N; //N的意思是最多能跳几层
- map<string, int> mp;
- map<int, string> mpback;
- int pop = ;
- string from, to;
- void addedge(int x, int y, int w) //把边保存起来的函数
- {
- edge a = {x, y, w}, b = {y, x, w};
- edges.push_back(a);
- edges.push_back(b);
- G[x].push_back(edges.size() - );
- G[y].push_back(edges.size() - );
- }
- void dfs(int x)//dfs建图
- {
- for (int i = ; i <= N; i++) //第一个几点就全部都是0,第二个节点就有变化了,不理解的话建议复制代码输出下这些数组
- {
- grand[x][i] = grand[grand[x][i - ]][i - ]; //倍增 2^i=2^(i-1)+2^(i-1)
- gw[x][i] = gw[x][i - ] + gw[grand[x][i - ]][i - ]; //维护一个距离数组
- //gwmax[x][i]=max(gwmax[x][i-1],gw[grand[x][i-1]][i-1]);
- // if(grand[x][i]==0) break;
- }
- for (int i = ; i < G[x].size(); i++)
- {
- edge e = edges[G[x][i]];
- if (e.to != grand[x][]) //这里我们保存的是双向边所以与他相连的边不是他父亲就是他儿子父亲的话就不能执行,不然就死循环了。
- {
- depth[e.to] = depth[x] + ; //他儿子的深度等于他爸爸的加1
- grand[e.to][] = x; //与x相连那个节点的父亲等于x
- gw[e.to][] = e.w; //与x相连那个节点的距离等于这条边的距离
- //gwmax[e.to][0]=e.w;
- dfs(e.to);//深搜往下面建
- }
- }
- }
- void Init()
- {
- //n为节点个数
- N = floor(log(pop + 0.0) / log(2.0));//最多能跳的2^i祖先
- depth[root] = ; //根结点的祖先不存在,用-1表示
- depth[] = -;
- memset(grand, , sizeof(grand));
- memset(gw, , sizeof(gw));
- dfs(root);//以根节点建树
- }
- int lca(int a, int b)
- {
- if (depth[a] > depth[b])
- {
- swap(a, b); //保证a在b上面,便于计算
- }
- int ans = ;
- for (int i = N; i >= ; i--) //类似于二进制拆分,从大到小尝试
- {
- if (depth[a] < depth[b] && depth[grand[b][i]] >= depth[a]) //a在b下面且b向上跳后不会到a上面
- {
- ans += gw[b][i], b = grand[b][i]; //先把深度较大的b往上跳
- }
- }
- if (a == b)
- {
- return a;
- }
- for (int j = N; j >= ; j--) //在同一高度了,他们一起向上跳,跳他们不相同节点,当全都跳完之后grand【a】【0】就是lca,上面有解释哈。
- {
- if (grand[a][j] != grand[b][j])
- {
- ans += gw[a][j];
- ans += gw[b][j];
- a = grand[a][j];
- b = grand[b][j];
- }
- }
- if (a != b) //a等于b的情况就是上面土色字体的那种情况
- {
- ans += gw[a][], ans += gw[b][];
- }
- return grand[a][];
- }
- void getnum(string x)
- {
- if (mp[x])
- {
- return ;
- }
- mp[x] = ++pop;
- mpback[pop] = x;
- return ;
- }
- int main()
- {
- root = ;
- cin >> n;
- for (int i = ; i <= n; i++)
- {
- cin >> from >> to;
- getnum(from);
- getnum(to);
- //cout << mp[from] << " " << mp[to] << endl;
- addedge(mp[from], mp[to], );
- }
- Init();
- cin >> m;
- for (int i = ; i <= m; i++)
- {
- cin >> from >> to;
- //getnum(from), getnum(to);
- cout << mpback[lca(mp[from], mp[to])] << endl;
- }
- }
codevs4605 在线单树不带权LCA
①倍增
- /* Huyyt */
- #include <bits/stdc++.h>
- using namespace std;
- const int maxn = ; //点的最大值
- const int maxl = ; //深度的最大值
- typedef struct
- {
- int from, to, w;
- } edge; //这个结构体用来存储边
- vector<edge> edges;
- vector<int> G[maxn];
- //保存边的数组
- int grand[maxn][maxl]; //x向上跳2^i次方的节点,x到他上面祖先2^i次方的距离
- int gw[maxn][maxl]; //维护距离的数组
- //int gwmax[maxn][maxl]; //维护边权最大值的数组
- int depth[maxn];//深度
- int root;
- int from, to;
- int n, m;
- int N; //N的意思是最多能跳几层
- void addedge(int x, int y, int w) //把边保存起来的函数
- {
- edge a = {x, y, w}, b = {y, x, w};
- edges.push_back(a);
- edges.push_back(b);
- G[x].push_back(edges.size() - );
- G[y].push_back(edges.size() - );
- }
- void dfs(int x)//dfs建图
- {
- for (int i = ; i <= N; i++) //第一个几点就全部都是0,第二个节点就有变化了,不理解的话建议复制代码输出下这些数组
- {
- grand[x][i] = grand[grand[x][i - ]][i - ]; //倍增 2^i=2^(i-1)+2^(i-1)
- gw[x][i] = gw[x][i - ] + gw[grand[x][i - ]][i - ]; //维护一个距离数组
- //gwmax[x][i]=max(gwmax[x][i-1],gw[grand[x][i-1]][i-1]);
- // if(grand[x][i]==0) break;
- }
- for (int i = ; i < G[x].size(); i++)
- {
- edge e = edges[G[x][i]];
- if (e.to != grand[x][]) //这里我们保存的是双向边所以与他相连的边不是他父亲就是他儿子父亲的话就不能执行,不然就死循环了。
- {
- depth[e.to] = depth[x] + ; //他儿子的深度等于他爸爸的加1
- grand[e.to][] = x; //与x相连那个节点的父亲等于x
- gw[e.to][] = e.w; //与x相连那个节点的距离等于这条边的距离
- //gwmax[e.to][0]=e.w;
- dfs(e.to);//深搜往下面建
- }
- }
- }
- void Init()
- {
- //n为节点个数
- N = floor(log(n + 0.0) / log(2.0));//最多能跳的2^i祖先
- depth[root] = ; //根结点的祖先不存在,用-1表示
- depth[] = -;
- memset(grand, , sizeof(grand));
- memset(gw, , sizeof(gw));
- dfs(root);//以根节点建树
- }
- int lca(int a, int b)
- {
- if (depth[a] > depth[b])
- {
- swap(a, b); //保证a在b上面,便于计算
- }
- int ans = ;
- for (int i = N; i >= ; i--) //类似于二进制拆分,从大到小尝试
- {
- if (depth[a] < depth[b] && depth[grand[b][i]] >= depth[a]) //a在b下面且b向上跳后不会到a上面
- {
- ans += gw[b][i], b = grand[b][i]; //先把深度较大的b往上跳
- }
- }
- if (a == b)
- {
- return a;
- }
- for (int j = N; j >= ; j--) //在同一高度了,他们一起向上跳,跳他们不相同节点,当全都跳完之后grand【a】【0】就是lca,上面有解释哈。
- {
- if (grand[a][j] != grand[b][j])
- {
- ans += gw[a][j];
- ans += gw[b][j];
- a = grand[a][j];
- b = grand[b][j];
- }
- }
- if (a != b) //a等于b的情况就是上面土色字体的那种情况
- {
- ans += gw[a][], ans += gw[b][];
- }
- return grand[a][];
- }
- int main()
- {
- root = ;
- cin >> n;
- for (int i = ; i <= n; i++)
- {
- cin >> to;
- if (to == )
- {
- root = i;
- continue;
- }
- addedge(to, i, );
- }
- Init();
- cin >> m;
- int anser = ;
- for (int i = ; i <= m; i++)
- {
- cin >> from >> to;
- from ^= anser;
- to ^= anser;
- anser = lca(from, to);
- cout << anser << endl;
- }
- }
②ST
- /*Huyyt*/
- #include<bits/stdc++.h>
- #define mem(a,b) memset(a,b,sizeof(a))
- #define pb push_back
- using namespace std;
- typedef long long ll;
- typedef unsigned long long ull;
- const int mod = 1e9 + ;
- const int gakki = + + + + 1e9;
- const int MAXN = 2e5 + , MAXM = 2e5 + ;
- int to[MAXM << ], nxt[MAXM << ], Head[MAXN], tot = ;
- inline void addedge(int u, int v)
- {
- to[++tot] = v;
- nxt[tot] = Head[u];
- Head[u] = tot;
- }
- int depth[ * MAXN], ver[ * MAXN], first[MAXN], dfs_clock = ;
- int dp[MAXN][];
- void dfs(int x, int fa, int deep)
- {
- ver[++dfs_clock] = x;
- first[x] = dfs_clock;
- depth[dfs_clock] = deep;
- for (int i = Head[x]; i; i = nxt[i])
- {
- int v = to[i];
- if (v != fa)
- {
- dfs(v, x, deep + );
- ver[++dfs_clock] = x;
- depth[dfs_clock] = deep;
- }
- }
- }
- void ST(int n)
- {
- for (int i = ; i <= n; i++)
- {
- dp[i][] = i;
- }
- for (int j = ; ( << j) <= n; j++)
- {
- for (int i = ; i + ( << j) - <= n; i++)
- {
- dp[i][j] = depth[dp[i][j - ]] < depth[dp[i + ( << (j - ))][j - ]] ? dp[i][j - ] : dp[i + ( << (j - ))][j - ];
- }
- }
- }
- int RMQ(int l, int r)
- {
- int k = (int)(log((double)(r-l+)) / log(2.0));
- return depth[dp[l][k]] < depth[dp[r - ( << k) + ][k]] ? dp[l][k] : dp[r - ( << k) + ][k];
- }
- int LCA(int u, int v)
- {
- int a = first[u], b = first[v];
- if (a > b)
- {
- swap(a, b);
- }
- int res = RMQ(a, b);
- return ver[res];
- }
- int main()
- {
- ios_base::sync_with_stdio();
- cin.tie();
- int root;
- int n, m, u, v;
- cin >> n;
- for (int i = ; i <= n; i++)
- {
- cin >> u;
- if (u == )
- {
- root = i;
- continue;
- }
- addedge(i, u), addedge(u, i);
- }
- dfs(root, , );
- ST(dfs_clock);
- int anser = ;
- cin >> m;
- for (int i = ; i <= m; i++)
- {
- cin >> u >> v;
- u = u ^ anser;
- v = v ^ anser;
- anser = LCA(u, v);
- cout << anser << endl;
- }
- return ;
- }
POJ1470 大量输入5e5询问LCA
①Tarjan
- #include<bits/stdc++.h>
- using namespace std;
- const int MAXN = ;
- const int MAXQ = ;//查询数的最大值
- inline int readint()
- {
- char c = getchar();
- int ans = ;
- while (c < '' || c > '')
- {
- c = getchar();
- }
- while (c >= '' && c <= '')
- {
- ans = ans * + c - '', c = getchar();
- }
- return ans;
- }
- //并查集部分
- int F[MAXN];//需要初始化为-1
- int find(int x)
- {
- if (F[x] == -)
- {
- return x;
- }
- return F[x] = find(F[x]);
- }
- void bing(int u, int v)
- {
- int t1 = find(u);
- int t2 = find(v);
- if (t1 != t2)
- {
- F[t1] = t2;
- }
- }
- //************************
- bool vis[MAXN];//访问标记
- int ancestor[MAXN];//祖先
- struct Edge
- {
- int to, next;
- } edge[MAXN * ];
- int head[MAXN], tot;
- void addedge(int u, int v)
- {
- edge[tot].to = v;
- edge[tot].next = head[u];
- head[u] = tot++;
- }
- struct Query
- {
- int q, next;
- int index;//查询编号
- } query[MAXQ * ];
- int answer[MAXQ];//存储最后的查询结果,下标0~Q-1
- int h[MAXQ];
- int tt;
- int Q;
- void add_query(int u, int v, int index)
- {
- query[tt].q = v;
- query[tt].next = h[u];
- query[tt].index = index;
- h[u] = tt++;
- query[tt].q = u;
- query[tt].next = h[v];
- query[tt].index = index;
- h[v] = tt++;
- }
- void init()
- {
- tot = ;
- memset(head, -, sizeof(head));
- tt = ;
- memset(h, -, sizeof(h));
- memset(vis, false, sizeof(vis));
- memset(F, -, sizeof(F));
- memset(ancestor, , sizeof(ancestor));
- }
- void LCA(int u)
- {
- ancestor[u] = u;
- vis[u] = true;
- for (int i = head[u]; i != -; i = edge[i].next)
- {
- int v = edge[i].to;
- if (vis[v])
- {
- continue;
- }
- LCA(v);
- bing(u, v);
- ancestor[find(u)] = u;
- }
- for (int i = h[u]; i != -; i = query[i].next)
- {
- int v = query[i].q;
- if (vis[v])
- {
- answer[query[i].index] = ancestor[find(v)];
- }
- }
- }
- bool flag[MAXN];
- int Count_num[MAXN];
- int main()
- {
- //freopen("in.txt","r",stdin);
- //freopen("out.txt","w",stdout);
- int n;
- int u, v, k;
- while (scanf("%d", &n) == )
- {
- init();
- memset(flag, false, sizeof(flag));
- for (int i = ; i <= n; i++)
- {
- u = readint();
- k = readint();
- while (k--)
- {
- v = readint();
- flag[v] = true;
- addedge(u, v);
- addedge(v, u);
- }
- }
- Q = readint();
- for (int i = ; i < Q; i++)
- {
- u = readint();
- v = readint();
- add_query(u, v, i);
- }
- int root;
- for (int i = ; i <= n; i++)
- if (!flag[i])
- {
- root = i;
- break;
- }
- LCA(root);
- memset(Count_num, , sizeof(Count_num));
- for (int i = ; i < Q; i++)
- {
- Count_num[answer[i]]++;
- }
- for (int i = ; i <= n; i++)
- if (Count_num[i] > )
- {
- printf("%d:%d\n", i, Count_num[i]);
- }
- }
- return ;
- }
POJ 1330
HDU 4547
SPOJ 10628 在线第K大点(主席树+LCA)
- /*SPOJ 10628
- 第一行两个整数N,M 1E5
- 第二行有N个整数,其中第i个整数表示点i的权值
- 后面N-1行每行两个整数(x,y),表示点x到点y有一条边
- 最后M行每行两个整数(u,v,k),表示一组询问*/
- /*Huyyt*/
- #include<bits/stdc++.h>
- #define inf 0x7fffffff
- #define ll long long
- #define N 100005
- #define M 2000005
- using namespace std;
- inline ll read()
- {
- ll x=,f=;char ch=getchar();
- while(ch>''||ch<''){if(ch=='-')f=-;ch=getchar();}
- while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
- return x*f;
- }
- int n,m,tot,sz,cnt,ind,last;
- int num[N],pos[N];
- int v[N],tmp[N],hash[N],root[N];
- int ls[M],rs[M],sum[M];
- int deep[N],fa[N][];
- struct data{int to,next;}e[];int head[N];
- void ins(int u,int v)
- {e[++cnt].to=v;e[cnt].next=head[u];head[u]=cnt;}
- void insert(int u,int v)
- {ins(u,v);ins(v,u);}
- int find(int x)
- {
- int l=,r=tot;
- while(l<=r)
- {
- int mid=(l+r)>>;
- if(hash[mid]<x)l=mid+;
- else if(hash[mid]==x)return mid;
- else r=mid-;
- }
- }
- void dfs(int x)
- {
- ind++;num[ind]=x;pos[x]=ind;
- for(int i=;i<=;i++)
- if((<<i)<=deep[x])fa[x][i]=fa[fa[x][i-]][i-];
- else break;
- for(int i=head[x];i;i=e[i].next)
- if(fa[x][]!=e[i].to)
- {
- deep[e[i].to]=deep[x]+;
- fa[e[i].to][]=x;
- dfs(e[i].to);
- }
- }
- int lca(int x,int y)
- {
- if(deep[x]<deep[y])swap(x,y);
- int t=deep[x]-deep[y];
- for(int i=;i<=;i++)
- if((<<i)&t)x=fa[x][i];
- for(int i=;i>=;i--)
- if(fa[x][i]!=fa[y][i])
- x=fa[x][i],y=fa[y][i];
- if(x==y)return x;
- return fa[x][];
- }
- void update(int l,int r,int x,int &y,int num)
- {
- y=++sz;
- sum[y]=sum[x]+;
- if(l==r)return;
- ls[y]=ls[x];rs[y]=rs[x];
- int mid=(l+r)>>;
- if(num<=mid)
- update(l,mid,ls[x],ls[y],num);
- else update(mid+,r,rs[x],rs[y],num);
- }
- int que(int x,int y,int rk)
- {
- int a=x,b=y,c=lca(x,y),d=fa[c][];
- a=root[pos[a]],b=root[pos[b]],c=root[pos[c]],d=root[pos[d]];
- int l=,r=tot;
- while(l<r)
- {
- int mid=(l+r)>>;
- int tmp=sum[ls[a]]+sum[ls[b]]-sum[ls[c]]-sum[ls[d]];
- if(tmp>=rk)r=mid,a=ls[a],b=ls[b],c=ls[c],d=ls[d];
- else rk-=tmp,l=mid+,a=rs[a],b=rs[b],c=rs[c],d=rs[d];
- }
- return hash[l];
- }
- int main()
- {
- n=read(),m=read();
- for(int i=;i<=n;i++)
- v[i]=read(),tmp[i]=v[i];
- sort(tmp+,tmp+n+);
- hash[++tot]=tmp[];
- for(int i=;i<=n;i++)
- if(tmp[i]!=tmp[i-])hash[++tot]=tmp[i];
- for(int i=;i<=n;i++)v[i]=find(v[i]);
- for(int i=;i<n;i++)
- {
- int u=read(),v=read();
- insert(u,v);
- }
- dfs();
- for(int i=;i<=n;i++)
- {
- int t=num[i];
- update(,tot,root[pos[fa[t][]]],root[i],v[t]);
- }
- for(int i=;i<=m;i++)
- {
- int x=read(),y=read(),rk=read();
- x^=last;
- last=que(x,y,rk);
- printf("%d",last);
- if(i!=m)printf("\n");
- }
- return ;
- }
HDU 3078 离线修改第K大点
0 a b 表示把点a的权改为b
k a b 表示求出从a到b的路径中,第K大的点权
①Tarjan
- /*
- 先用离线Tarjan把每个Query树链的LCA求出来
- LCA中对连接树Dfs的时候,令p[v]=u,记录v的前驱
- LCA结束后,对于每个Query:
- 从u开始回溯到LCA,记录值。从v开始回溯到LCA,记录值
- 再加上LCA这个点的值,形成一条完整树链。特判树链长度是否小于K
- 对树链中的值,从大到小排序,取第K大即可
- */
- /*Huyyt*/
- #include<bits/stdc++.h>
- using namespace std;
- #define maxn 80005
- int head[maxn],qhead[maxn],lag[maxn],kth[maxn],tot1,tot2,f[maxn],vis[maxn],ancestor[maxn],p[maxn];
- bool cmp(int a,int b) {return a>b;}
- struct Edge
- {
- int to,next;
- }e[maxn*];
- struct Query
- {
- int from,to,next,idx;
- }q[maxn*];
- void addedge(int u,int v)
- {
- e[tot1].to=v;
- e[tot1].next=head[u];
- head[u]=tot1++;
- }
- void addquery(int u,int v,int idx)
- {
- q[tot2].from=u;
- q[tot2].to=v;
- q[tot2].next=qhead[u];
- q[tot2].idx=idx;
- qhead[u]=tot2++;
- }
- int find(int x) {return x!=f[x]?f[x]=find(f[x]):x;}
- void Union(int u,int v)
- {
- u=find(u),v=find(v);
- if(u!=v) f[v]=u;
- }
- void LCA(int u)
- {
- vis[u]=true;
- f[u]=u;
- for(int i=head[u];i!=-;i=e[i].next)
- {
- int v=e[i].to;
- if(!vis[v])
- {
- p[v]=u;
- LCA(v);
- Union(u,v);
- }
- }
- for(int i=qhead[u];i!=-;i=q[i].next)
- {
- int v=q[i].to;
- if(vis[v]) ancestor[q[i].idx]=find(v);
- //or storage e[i].lca=e[i^1].lca=find(v)
- }
- }
- int main()
- {
- //freopen("in.txt","r",stdin);
- int T,n,m,u,v,c,cmd;
- scanf("%d%d",&n,&m);
- tot1=tot2=;
- memset(head,-,sizeof(head));
- memset(qhead,-,sizeof(qhead));
- memset(vis,,sizeof(vis));
- for(int i=;i<=n;i++) scanf("%d",&lag[i]);
- for(int i=; i<n-; i++)
- {
- scanf("%d%d",&u,&v);
- addedge(u,v);
- addedge(v,u);
- }
- for(int i=; i<m; i++)
- {
- scanf("%d%d%d",&cmd,&u,&v);
- if(cmd==) lag[u]=v;
- else
- {
- addquery(u,v,i);
- addquery(v,u,i);
- kth[i]=cmd;
- }
- }
- LCA();
- for(int i=; i<tot2; i=i+)
- {
- int u=q[i].from,v=q[i].to,idx=q[i].idx;
- int ed=ancestor[idx];
- vector<int> chain;
- while(u!=ed) chain.push_back(lag[u]),u=p[u];
- while(v!=ed) chain.push_back(lag[v]),v=p[v];
- chain.push_back(lag[ed]);
- if(chain.size()<kth[idx]) {printf("invalid request!\n");continue;}
- else
- {
- sort(chain.begin(),chain.end(),cmp);
- printf("%d\n",chain[kth[idx]-]);
- }
- }
- }
②ST
- /*Huyyt*/
- #include<bits/stdc++.h>
- using namespace std;
- const int maxn=;
- int pre[maxn],E[maxn*],dep[maxn*],pos[maxn],vis[maxn];
- int d[maxn*][],val[maxn],num,path[maxn];
- int N,Q;
- vector<int> g[maxn];
- void init()
- {
- for(int i=;i<=N;i++)g[i].clear();
- num=;
- memset(pos,-,sizeof(pos));
- memset(vis,,sizeof(vis));
- }
- void dfs(int u,int depth)
- {
- E[++num]=u,dep[num]=depth;
- if(pos[u]==-)pos[u]=num;
- vis[u]=;
- int len=g[u].size();
- for(int i=;i<len;i++)
- {
- int v=g[u][i];
- if(vis[v])continue;
- pre[v]=u;
- dfs(v,depth+);
- E[++num]=u,dep[num]=depth;
- }
- }
- void initRMQ(int n)
- {
- for(int i=;i<=n;i++)d[i][]=i;
- for(int j=;(<<j)<=n;j++)
- for(int i=;i+(<<j)<=n;i++)
- {
- int x=d[i][j-],y=d[i+(<<(j-))][j-];
- if(dep[x]<dep[y])d[i][j]=x;
- else d[i][j]=y;
- }
- }
- int LCA(int u,int v)
- {
- int x=pos[u],y=pos[v];
- if(x>y)swap(x,y);
- int k=;
- while((<<(k+))<=y-x+)k++;
- int a=d[x][k],b=d[y-(<<k)+][k];
- if(dep[a]<dep[b])return E[a];
- else return E[b];
- }
- void solve(int k,int u,int v)
- {
- int fa=LCA(u,v);
- int cnt=;
- while(u!=fa){path[cnt++]=val[u];u=pre[u];}
- while(v!=fa){path[cnt++]=val[v];v=pre[v];}
- path[cnt++]=val[fa];
- sort(path,path+cnt,greater<int>());
- if(cnt<k)printf("invalid request!\n");
- else printf("%d\n",path[k-]);
- }
- int main()
- {
- while(scanf("%d%d",&N,&Q)!=EOF)
- {
- for(int i=;i<=N;i++)scanf("%d",&val[i]);
- init();
- for(int i=;i<N;i++)
- {
- int u,v;
- scanf("%d%d",&u,&v);
- g[u].push_back(v);
- g[v].push_back(u);
- }
- dfs(,);
- initRMQ(num);
- while(Q--)
- {
- int k,a,b;
- scanf("%d%d%d",&k,&a,&b);
- if(!k)val[a]=b;
- else solve(k,a,b);
- }
- }
- return ;
- }
- /*Huyyt*/
- #include<bits/stdc++.h>
- using namespace std;
- #define N 80010
- int __pow[];
- int fa[N],val[N],p[N];
- int node[*N],first[N],dep[*N],dp[*N][];
- bool vis[N];
- vector<int>e[N];
- void dfs(int &index , int u ,int d , int par)
- {
- ++index; vis[u] = true;
- first[u] = index; node[index] = u; dep[index] = d; fa[u] = par;
- for(int i=; i<e[u].size(); i++)
- if(!vis[e[u][i]])
- {
- dfs(index , e[u][i] , d+ , u);
- ++index;
- node[index] = u; dep[index] = d;
- }
- }
- void ST(int n)
- {
- int K = (int)(log((double)n) / log(2.0));
- for(int i=; i<=n; i++) dp[i][] = i;
- for(int j=; j<=K; j++)
- for(int i=; i+__pow[j]- <= n ; i++)
- {
- int a = dp[i][j-];
- int b = dp[i+__pow[j-]][j-];
- if(dep[a] < dep[b]) dp[i][j] = a;
- else dp[i][j] = b;
- }
- }
- int RMQ(int x ,int y)
- {
- int K = (int)(log((double)(y-x+)) / log(2.0));
- int a = dp[x][K];
- int b = dp[y-__pow[K]+][K];
- if(dep[a] < dep[b]) return a;
- else return b;
- }
- int LCA(int u ,int v)
- {
- int x = first[u];
- int y = first[v];
- if(x > y) swap(x,y);
- int index = RMQ(x,y);
- return node[index];
- }
- bool cmp(int a, int b)
- {
- return a > b;
- }
- void path(int &index , int s , int t)
- {
- while(s != t)
- {
- p[index++] = val[s];
- s = fa[s];
- }
- p[index++] = val[t];
- }
- void solve(int kth , int u,int v)
- {
- int lca = LCA(u,v);
- int tot = ;
- path(tot,u,lca);
- path(tot,v,lca);
- tot--;
- if(kth > tot)
- {
- printf("invalid request!\n");
- return ;
- }
- sort(p,p+tot,cmp);
- printf("%d\n",p[kth-]);
- }
- int main()
- {
- for(int i=; i<; i++) __pow[i] = << i;
- int n,q;
- scanf("%d%d",&n,&q);
- for(int i=; i<=n; i++) scanf("%d",&val[i]);
- for(int i=; i<n; i++)
- {
- int u,v;
- scanf("%d%d",&u,&v);
- e[u].push_back(v);
- e[v].push_back(u);
- }
- int tot = ;
- memset(vis,false,sizeof(vis));
- dfs(tot,,,-);
- ST(tot);
- while(q--)
- {
- int op;
- scanf("%d",&op);
- if(op == )
- {
- int x,w;
- scanf("%d%d",&x,&w);
- val[x] = w;
- }
- else
- {
- int u,v;
- scanf("%d%d",&u,&v);
- solve(op,u,v);
- }
- }
- return ;
- }
Codeforces 932D 倍增维护
给你一个有根树根的下标为1 每个节点有一个权值 根的权值为0 总共有4e5次 强制在线操作
操作1:在R节点下面加一个权值为W的新节点
操作2:询问从R开始朝根节点走 走到第一个权值不小于它的节点且经过的节点权值和不大于W的最长长度
维护两个数组 一个是father[i][j]表示在i之上 第2^j个比i权值大的点 第二个是sum[i][j]表示从i到第2^j个比i权值大的点途中经过点的权值和(不包括W[i])
- /*Huyyt*/
- #include<bits/stdc++.h>
- #define mem(a,b) memset(a,b,sizeof(a))
- #define pb push_back
- using namespace std;
- typedef long long ll;
- typedef unsigned long long ull;
- const ll LLmaxn = 2e18;
- const int maxn = ;
- inline long long read()
- {
- char c = getchar();
- long long ans = ;
- while (c < '' || c > '')
- {
- c = getchar();
- }
- while (c >= '' && c <= '')
- {
- ans = ans * + c - '', c = getchar();
- }
- return ans;
- }
- ll w[maxn];
- ll father[maxn][];
- ll sum[maxn][];
- int cnt = ;
- ll last = ;
- void add(ll a, ll b)
- {
- w[++cnt] = b;
- if (w[a] >= w[cnt])
- {
- father[cnt][] = a;
- }
- else
- {
- for (int i = ; i >= ; i--)
- {
- if (w[father[a][i]] < w[cnt])
- {
- a = father[a][i];
- }
- }
- father[cnt][] = father[a][];
- }
- if (father[cnt][] == )
- {
- sum[cnt][] = LLmaxn;
- }
- else
- {
- sum[cnt][] = w[father[cnt][]];
- }
- for (int i = ; i <= ; i++)
- {
- father[cnt][i] = father[father[cnt][i - ]][i - ];
- if (father[cnt][i] == )
- {
- sum[cnt][i] = LLmaxn;
- }
- else
- {
- sum[cnt][i] = sum[cnt][i - ] + sum[father[cnt][i - ]][i - ];
- }
- }
- }
- ll query(ll a, ll b)
- {
- if (w[a] > b)
- {
- return ;
- }
- b -= w[a];
- ll ans = ;
- for (int i = ; i >= ; i--)
- {
- if (b >= sum[a][i])
- {
- b -= sum[a][i];
- ans += (1LL << i);
- a = father[a][i];
- }
- }
- return ans;
- }
- void init()
- {
- w[] = LLmaxn;
- w[] = ;
- father[][] = ;
- mem(sum[], 0x3f);
- }
- ll a, b;
- int main()
- {
- //cout<<LLmaxn<<endl;
- init();
- int n, Q;
- int ch;
- n = read();
- for (int i = ; i <= n; i++)
- {
- ch = read();
- a = read();
- b = read();
- a ^= last;
- b ^= last;
- if (ch == )
- {
- add(a, b);
- }
- else
- {
- last = query(a, b);
- cout << last << endl;
- }
- }
- return ;
- }
Codeforces 980E
给你N个点 组成的一颗树 分别从1标号到N 每个点的粉丝数量为2^i个
要求是选择K个点删除 使得剩下没被删的点保持连通且剩下的粉丝数量最大
一旦某个点被删除则其不能通过且该点的粉丝数量清零
假如做法顺着做 找出需要删除那些点的话 因为要保证连通性所以删除一个点需要删除掉他所有子树的点 不好做
题目提示你K<N 所以点N是一定可以保留的 就以N为根倍增预处理祖先 倒着做 找出不需要删除的点即可
- /* Huyyt */
- #include <bits/stdc++.h>
- #define mem(a,b) memset(a,b,sizeof(a))
- #define mkp(a,b) make_pair(a,b)
- #define pb push_back
- using namespace std;
- typedef long long ll;
- const long long mod = 1e9 + ;
- const int N = 1e6 + ;
- inline int readint()
- {
- char c = getchar();
- int ans = ;
- while (c < '' || c > '')
- {
- c = getchar();
- }
- while (c >= '' && c <= '')
- {
- ans = ans * + c - '', c = getchar();
- }
- return ans;
- }
- vector<int> tree[N];
- bool check[N];
- int father[N][];
- int deep[N];
- void dfs(int x, int level)
- {
- for (int i = ; father[father[x][i]][i]; i++)
- {
- father[x][i + ] = father[father[x][i]][i];
- }
- deep[x] = level;
- for (int i = ; i < tree[x].size(); i++)
- {
- int to = tree[x][i];
- if (to == father[x][])
- {
- continue;
- }
- father[to][] = x;
- dfs(to, level + );
- }
- }
- int main()
- {
- int n, k;
- n = readint(), k = readint();
- int u, v;
- for (int i = ; i < n; i++)
- {
- u = readint(),v = readint();
- tree[u].pb(v);
- tree[v].pb(u);
- }
- k = n - k;
- k--, check[n] = ;
- dfs(n, );
- for (int i = n - ; i >= && k; i--)
- {
- int aim = -;
- int now = i;
- if (check[i])
- {
- continue;
- }
- for (int j = ; j >= ; j--)
- {
- if (father[now][j] == || check[father[now][j]])
- {
- continue;
- }
- now = father[now][j];
- }
- if (deep[i] - deep[now] + <= k)
- {
- now = i;
- while (now != && !check[now])
- {
- check[now] = ;
- k--;
- now = father[now][];
- }
- }
- }
- for (int i = ; i <= n - ; i++)
- {
- if (!check[i])
- {
- cout << i << " ";
- }
- }
- return ;
- }
LCA统计的更多相关文章
- 【BZOJ-3910】火车 倍增LCA + 并查集
3910: 火车 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 262 Solved: 90[Submit][Status][Discuss] De ...
- 洛谷八月月赛Round1凄惨记
个人背景: 上午9:30放学,然后因为学校举办读书工程跟同学去书城选书,中午回来开始打比赛,下午又回老家,中间抽出一点时间调代码,回家已经8:50了 也许是7月月赛时“连蒙带骗”AK的太幸运然而因同学 ...
- UOJ261 【NOIP2016】天天爱跑步
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000作者博客:http://www.cnblogs.com/ljh2000-jump/转 ...
- BZOJ4719 [Noip2016]天天爱跑步
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000作者博客:http://www.cnblogs.com/ljh2000-jump/转 ...
- UOJ#400. 【CTSC2018】暴力写挂
传送门 看到要求两棵树的 \(lca\) 深度不太好操作 考虑枚举第二棵树的 \(lca\),这样剩下的都是只和第一棵树有关的 而注意到 \(dis(x,y)=d(x)+d(y)-2d(lca(x,y ...
- JZOJ.5305【NOIP2017模拟8.18】C
Description
- BZOJ4543 [POI2014]Hotel加强版
题意 有一个树形结构,每条边的长度相同,任意两个节点可以相互到达.选3个点.两两距离相等.有多少种方案? 数据范围:n<=100000 分析 参照小蒟蒻yyb的博客. 我们先考虑一个\(O(n^ ...
- CODEVS——T 1036 商务旅行
http://codevs.cn/problem/1036/ 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 题目描述 Descript ...
- 0917CSP-S模拟测试赛后总结
机房搬家后的首战,便是失利. 依旧是挂掉了.这次状态有大问题. 然而状态的问题归根结底还是实力不行. 大约一个小时左右我拿到了T1的部分分.赛时判断了一下大概是高分. (不过赛后发现确实不算什么太高的 ...
随机推荐
- java:Springmvc框架1(基本配置,注解配置,转换器引入)
1.springmvc01:(基本配置) web.xml: <?xml version="1.0" encoding="UTF-8"?> <w ...
- 深入理解.NET Core的基元(二)
原文:Deep-dive into .NET Core primitives, part 2: the shared framework作者:Nate McMaster译文:深入理解.NET Core ...
- AJAX中同步和异步的区别和使用场景
一.简介Ajax请求最重要的问题是代码执行的顺序.最长遇到的问题是,我们定义一个变量接收ajax异步请求的返回结果,后续代码使用,然而后续代码在使用时该变量为初始值,始终得不到想要的结果!!!二.示例 ...
- C++中sort函数使用方法
一.sort函数 1.sort函数包含在头文件为#include<algorithm>的c++标准库中,调用标准库里的排序方法可以实现对数据的排序,但是sort函数是如何实现的,我们不用考 ...
- cocos2dx基础篇(1) Cocos2D-X项目创建
已经入行工作半年多时间了,以前都是把这些东西记录在有道云上面的,现在抽出些时间把以前的笔记腾过来. 具体的环境配置就不用说了,因为现在已经是2018年,只需要下载对应版本解压后就能使用,不用再像多年前 ...
- LeetCode.949-给定数字的最大时间(Largest Time for Given Digits)
这是悦乐书的第363次更新,第391篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第225题(顺位题号是949).给定4个整数组成的数组,返回最大的24小时时间. 最小的 ...
- H3C版本升级
H3C S5500和S3100都可以通过TFTP方式进行升级,1.设置交换机的vlan1的ip地址,如10.10.10.2/242.设置电脑和交换机连接的ip地址,如10.10.10.1/243.在交 ...
- JWT的实现原理
前言最近在做一个python项目的改造,将python项目重构为java项目,过程中遇到了这个知识点,觉得这个蛮实用的,所以下班后回来趁热打铁写下这篇总结,希望后面的人能够有所借鉴,少走弯路. 一.优 ...
- 【嵌入式开发】Raspberry Pi 树莓派性能测试
Raspberry Pi 树莓派性能测试 目录: CPU Linpack基准测试 源码 编译/运行 结果 Whetstone/Dhrystone综合基准测试 源码 编译/运行 结果 OpenSSL安全 ...
- IDEA 如何批量修改变量名
修改前的变量 System.out.println("bbbbb"); System.out.println("bbbbb"); System.out.prin ...