2024-03-10

2024-03-10

雨天的尾巴(线段树合并)

  • 每个点建动态开点权值线段树,把每棵树的根记到 \(root\)

跟 gyx 学长学的线段树小窍门%%%

  1. \(Node\) 结构体中重载 \(+\) 号代替 \(update\)
  2. \(query\) 函数类型设置为 \(Node\) 方便合并答案

第 2 条在这题里面没有用到

关于第一条
加法返回的结果可能使结构体中某些量被覆盖而丢失原来存的数
算上这次我已经因为这个寄了两回了🤣
第二条还是可以用用的,关于第一条……乖乖写 update 吧🤔

  • 路径修改转化为树上差分
    xy 路径上所有点 +1
    转化为
    x, y 位置 +1lca(x,y),fa[lca(x,y)] 位置 -1

lca 可以用 倍增/树链剖分 实现

  • 处理完修改 一遍 dfs 进行线段树合并

mergetr 传参数的时候传成 u, v 了,感谢 ztx 指出错误%%%

#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>

using namespace std;

const int N=1e5+10;
int MX;

struct OPT {
	int x,y,k;
}op[N];
struct Node {
	int ls,rs;
	int mxn,mxk;
}tr[N*60];

int root[N];
int idnode=0;

void update(int u) {
	if(tr[tr[u].ls].mxn>=tr[tr[u].rs].mxn)
		tr[u].mxn=tr[tr[u].ls].mxn,tr[u].mxk=tr[tr[u].ls].mxk;
	else tr[u].mxn=tr[tr[u].rs].mxn,tr[u].mxk=tr[tr[u].rs].mxk;
}

int update(int u,int lft,int rgh,int k,int f) {
	if(!u) u=++idnode;
	if(lft==rgh) {
		tr[u].mxn+=f,tr[u].mxk=lft;
		return u;
	}
	int mid=lft+rgh>>1;
	if(k<=mid) tr[u].ls=update(tr[u].ls,lft,mid,k,f);
	else tr[u].rs=update(tr[u].rs,mid+1,rgh,k,f);
	update(u);
	return u;
}

int mergetr(int u,int v,int lft,int rgh) {
	if(!u||!v) return u+v;
	if(lft==rgh) {
		tr[u].mxn+=tr[v].mxn,tr[u].mxk=lft;
		return u;
	}
	int mid=lft+rgh>>1;
	tr[u].ls=mergetr(tr[u].ls,tr[v].ls,lft,mid);
	tr[u].rs=mergetr(tr[u].rs,tr[v].rs,mid+1,rgh);
	update(u);
	return u;
}

int n,m;
int hd[N],edg[N*2],nxt[N*2],idx;

void adde(int u,int v) {
	edg[idx]=v,nxt[idx]=hd[u],hd[u]=idx++;
}

int fa[N],sn[N];
int dep[N],top[N],siz[N];

void dfs1(int u,int father) {
	fa[u]=father,siz[u]=1,dep[u]=dep[father]+1;
	for(int i=hd[u];~i;i=nxt[i]) {
		int v=edg[i];
		if(v==father) continue;
		dfs1(v,u);
		siz[u]+=siz[v];
		if(siz[v]>siz[sn[u]]) sn[u]=v;
	}
}

void dfs2(int u,int tp) {
	top[u]=tp;
	if(!sn[u]) return;
	dfs2(sn[u],tp);
	for(int i=hd[u];~i;i=nxt[i]) {
		int v=edg[i];
		if(v==fa[u]||v==sn[u]) continue;
		dfs2(v,v);
	}
}

int lca(int u,int v) {
	while(top[u]!=top[v]) {
		if(dep[top[u]]<dep[top[v]]) swap(u,v);
		u=fa[top[u]];
	}
	return dep[u]<dep[v]?u:v;
}

int ans[N];

void merge_dfs(int u) {
	for(int i=hd[u];~i;i=nxt[i]) {
		int v=edg[i];
		if(v==fa[u]) continue;
		merge_dfs(v);
		root[u]=mergetr(root[u],root[v],1,MX);
	}
	if(tr[root[u]].mxn) ans[u]=tr[root[u]].mxk;
}

int main() {
	memset(hd,-1,sizeof(hd));
	scanf("%d%d",&n,&m);
	for(int i=1;i<n;i++) {
		int u,v;
		scanf("%d%d",&u,&v);
		adde(u,v),adde(v,u);
	}
	dfs1(1,0);
	dfs2(1,1);
	for(int i=1;i<=m;i++) {
		scanf("%d%d%d",&op[i].x,&op[i].y,&op[i].k);
		MX=max(MX,op[i].k);
	}
	for(int i=1;i<=m;i++) {
		int x=op[i].x,y=op[i].y,k=op[i].k;
		int z=lca(x,y),w=fa[z];
		root[x]=update(root[x],1,MX,k,1);
		root[y]=update(root[y],1,MX,k,1);
		root[z]=update(root[z],1,MX,k,-1);
		root[w]=update(root[w],1,MX,k,-1);
	}
	merge_dfs(1);
	for(int i=1;i<=n;i++) printf("%d\n",ans[i]);
	
	return 0;
} 

Riddle

前天看到 bpc 在做的题%%%
2-SAT,前几天比赛前打板子刚复习了一下,练一练

还没做出来,出学校hh,回来再写

upd:调出来了

posted @ 2024-03-10 11:41  OrangeStar*  阅读(11)  评论(0编辑  收藏  举报