• 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
    ",ans[i]);
    }
  • 相关阅读:
    eclipse中的项目如何打成war包
    【SVN】Please execute the 'Cleanup' command.
    2021.06.02模拟赛DP2
    2021.05.26模拟赛 DP1
    状压DP
    高斯消元
    矩阵快速幂
    2021.05.10讲题
    Luogu P2152[SDOI 2009]Super GCD
    Tarjan
  • 原文地址:https://www.cnblogs.com/zhanglichen/p/15021764.html
Copyright © 2020-2023  润新知