P4556 [Vani有约会]雨天的尾巴 /【模板】线段树合并
每个节点上开一个cnti数组表示i这个数字出现了多少次,那么节点i上出现最多的数字就是cnt数组的最大值。
然后每次的操作可以调整为:
在u v上打一个+1的标记,在uv的lca上打一个-1的标记,在lca的父亲上打一个-1的标记。
然后打完标记后从叶子开始启发式的向上合并。
假设当前节点是u。
首先比较u的线段树sz和u的儿子们的最大线段树sz,小的往大的上面合并。
然后剩下的线段树无脑往这个最大的线段树上合并,那么最终的线段树就是u的状态。
然后题目要求输出最小的编号。
这里考虑直接在线段树上维护。
即id[i]表示节点i所在的区间内的最大值的最小编号。
然后往上pushup的时候应该是可以完全合并的。
另外,求lca可以直接倍增。
注意坑点:当一个点上最大次数为0的时候答案是0,不判断的话应该会输出1
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
const int M=maxn*80;
int tot;
int c[M],id[M],lson[M],rson[M],sz[M],T[maxn];
void pushup (int newRoot) {
c[newRoot]=max(c[lson[newRoot]],c[rson[newRoot]]);
if (c[lson[newRoot]]==c[newRoot]) id[newRoot]=id[lson[newRoot]];
else id[newRoot]=id[rson[newRoot]];
sz[newRoot]=sz[lson[newRoot]]+sz[rson[newRoot]]+1;
}
int up (int i,int l,int r,int p,int v) {
int newRoot=i;
if (!newRoot) newRoot=++tot,sz[newRoot]=1;
if (l==r) {
c[newRoot]+=v;
id[newRoot]=l;
return newRoot;
}
int mid=(l+r)>>1;
if (p<=mid) lson[newRoot]=up(lson[newRoot],l,mid,p,v);
if (p>mid) rson[newRoot]=up(rson[newRoot],mid+1,r,p,v);
pushup(newRoot);
return newRoot;
}
int merge (int x,int y,int l,int r) {
//合并根为x和y的线段树,返回新的根
if (!x) return y;
if (!y) return x;
if (l==r) {
c[x]+=c[y];
return x;
}
if (sz[x]<sz[y]) swap(x,y);
int mid=(l+r)>>1;
lson[x]=merge(lson[x],lson[y],l,mid);
rson[x]=merge(rson[x],rson[y],mid+1,r);
pushup(x);
return x;
}
int n;
vector<int> g[maxn];
int h[maxn],father[25][maxn];
void dfs (int x) {
for (int y:g[x]) {
if (y==father[0][x]) continue;
father[0][y]=x;
h[y]=h[x]+1;
dfs(y);
}
}
int lca (int x,int y) {
if (h[x]<h[y]) swap(x,y);
for (int i=20;i>=0;i--) {
if (h[x]-h[y]>>i) x=father[i][x];
}
if (x==y) return x;
for (int i=20;i>=0;i--) {
if (father[i][x]!=father[i][y]) {
x=father[i][x];
y=father[i][y];
}
}
return father[0][x];
}
int ans[maxn];
void dfs1 (int x) {
for (int y:g[x]) {
if (y==father[0][x]) continue;
dfs1(y);
}
int maxson=-1,u=0;
for (int y:g[x]) {
if (y==father[0][x]) continue;
if (sz[T[y]]>maxson) {
maxson=sz[T[y]];
u=y;
}
}
if (u) T[x]=merge(T[x],T[u],1,1e5);
for (int y:g[x]) {
if (y==father[0][x]) continue;
if (y==u) continue;
T[x]=merge(T[x],T[y],1,1e5);
}
ans[x]=id[T[x]];
if (c[T[x]]==0) ans[x]=0;
}
int m;
int main () {
scanf("%d%d",&n,&m);
for (int i=1;i<n;i++) {
int x,y;
scanf("%d%d",&x,&y);
g[x].push_back(y);
g[y].push_back(x);
}
dfs(1);
for (int i=1;i<=20;i++) {
for (int j=1;j<=n;j++) {
father[i][j]=father[i-1][father[i-1][j]];
}
}
while (m--) {
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
T[x]=up(T[x],1,1e5,z,1);
T[y]=up(T[y],1,1e5,z,1);
T[lca(x,y)]=up(T[lca(x,y)],1,1e5,z,-1);
T[father[0][lca(x,y)]]=up(T[father[0][lca(x,y)]],1,1e5,z,-1);
}
dfs1(1);
for (int i=1;i<=n;i++) printf("%d\n",ans[i]);
}