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的部分分.赛时判断了一下大概是高分. (不过赛后发现确实不算什么太高的 ...
随机推荐
- BOSCH汽车工程手册————自适应巡航速度控制ACC
驾驶员通过自动速度控制器操纵键,将汽车行驶速度控制在预设的期望速度上. ACC系统则在自动速度控制的基础上检测本车到前面行驶汽车的距离以及相对速度,以及其他车道上的信息. 利用这些数据就能控制两车之间 ...
- Anaconda快捷键
ctr+1 注释多行 ctr+4 包裹注释多行 ctr+d 删除一行
- sklearn.feature_extraction.DictVectorizer
sklearn.feature_extraction.DictVectorizer:将字典组成的列表转换成向量.(将特征与值的映射字典组成的列表转换成向量) 1. 特征矩阵行代表数据,列代表特征,0表 ...
- [Flask]常用过滤器-控制字符串
truncate: 字符串截断 <p>{{ 'hello every one' | truncate(9)}}</p> length:获取列表长度 <p>{{ [, ...
- Python中的IndentationError解决
用Python .join拼接SQL的时候遇到一个错误:TypeError: cannot concatenate 'str' and 'dict' objects,检查了一下确认是join了两个类型 ...
- python之reportlab生成PDF文件
项目需要,需要自动生成PDF测试报告.经过对比之后,选择使用了reportlab模块. 项目背景:开发一个测试平台,供测试维护测试用例,执行测试用例,并且生成测试报告(包含PDF和excel),将生成 ...
- asp.net mvc 依赖注入Ninject
1.安装Ninject 2.使用Ninject 一 安装Ninject Nuget:Ninject 二 使用Ninject public interface IStudent { string Get ...
- delphi数组如何初始化
https://wenda.so.com/q/1535561587217078delphi数组如何初始化rosegirl09112级分类:其他被浏览44次2018.07.01检举满意答案 csx330 ...
- golang remote debug和docker debug
在编写 Go 代码的时候,因为很多时候都是需要调试服务器上的代码的,作为一个年长的工程师,肯定不能用 log.Printf 来调试问题,所以我选择了 delve 这个工具,通过 delve 我可以像本 ...
- PHP操作redis部分命令
//连接本地的 Redis 服务 $redis = new Redis(); $redis->connect('127.0.0.1', 6379); $redis->auth('12345 ...