[国家集训队] 旅游 题解

从上午打到下午,甚至直接重构了一遍

solve

  • 有如下需要做的
    • 单点修
    • 区间取反(?)
    • 区间求最大&&最小&&和
  • 发现涉及带修区间问题,考虑线段树
  • 在一棵树上处理显然很费劲,直接祭出top tree树剖
  • 然后就没了
  • 0为根,那么直接给点都++
  • 应该没有唐必把要修的值++并把边的输入顺序++的吧
  • 应该吧
  • 注意的是:需要下放边权,然后在update及query时要传dfn[x]+1,msjing传的dfn[son[x]]然后炸了;取反时要注意!取反后max和min会对调

下放边权:考虑树的性质,直接把边权给儿子就行

变量声明

int n,m,a[maxn];
int fa[maxn],dep[maxn],siz[maxn],son[maxn],top[maxn];
int dfn[maxn],rnk[maxn],cnt;
struct _ {int l,r,sum,minn,maxx,lazy=1;}tree[maxn<<2];
int h[maxn],to[maxn],nxt[maxn],tot,w[maxn];
pair<int,int> path[maxn];
  • n,m,a[]:点数,询问数,初始点权
  • fa[],dep[],siz[],son[],top[]:节点 x 在树上的父亲,节点 x 在树上的深度,节点 x 的子树的节点个数,节点 x 的 重儿子,x 所在 重链 的顶部节点
  • dfn[],rnk[],cnt:x 的 DFS 序,也是其在线段树中的编号,DFS 序所对应的节点编号,有 rnk(dfn(x))=x,求dfs序用
    struct _ {int l,r,sum,minn,maxx,lazy=1;}tree[maxn<<2];int h[maxn],to[maxn],nxt[maxn],tot,w[maxn];:线段树,不多说
  • pair<int,int> path[maxn];:记录每一条边

代码部分实现

void dfs1(int x)
{
	son[x]=-1;siz[x]=1;
	for (int i=h[x];i;i=nxt[i])
	{
		int y=to[i];
		if (dep[y]) continue;
		a[y]=w[i];
		dep[y]=dep[x]+1;
		fa[y]=x;
		dfs1(y);
		siz[x]+=siz[y];
		if (son[x] == -1 || siz[y]>siz[son[x]]) son[x]=y;
	}
}
void dfs2(int x,int t)
{
	top[x]=t;
	cnt++;
	dfn[x]=cnt;rnk[cnt]=x;
	if (son[x] == -1) return;
	dfs2(son[x],t);
	for (int i=h[x];i;i=nxt[i])
	{
		int y=to[i];
		if (y == son[x] || y == fa[x]) continue;
		dfs2(y,y);
	}
}
  • 线段树上下放(注意标记下放后maxx和minn的处理)
void pushup(int rt)
{
	tree[rt].sum=tree[lson].sum+tree[rson].sum;
	tree[rt].maxx=max(tree[lson].maxx,tree[rson].maxx);
	tree[rt].minn=min(tree[lson].minn,tree[rson].minn);
}
void pushdown(int rt)
{
	if (tree[rt].lazy == -1)
	{
		tree[rt].lazy=1;
		tree[lson].lazy*=-1;tree[rson].lazy*=-1;
		tree[lson].sum*=-1;tree[rson].sum*=-1;
		tree[lson].maxx*=-1;tree[lson].minn*=-1;swap(tree[lson].maxx,tree[lson].minn);
		tree[rson].maxx*=-1;tree[rson].minn*=-1;swap(tree[rson].maxx,tree[rson].minn);
	}
}
  • 线段树建图
void build(int rt,int l,int r)
{
	tree[rt].l=l;tree[rt].r=r;
	if (l == r) {tree[rt].sum=tree[rt].maxx=tree[rt].minn=a[rnk[l]];return;}
	int mid=(l+r) >> 1;
	build(lson,l,mid);build(rson,mid+1,r);
	pushup(rt);
}
  • 区间取反
void add1(int x,int y)
{
	while (top[x]!=top[y])
	{
		if (dep[top[x]]<dep[top[y]]) swap(x,y);
		update_turn(1,dfn[top[x]],dfn[x]);
		x=fa[top[x]];
	}
	if(dep[x]>dep[y]) swap(x,y);
	update_turn(1,dfn[x]+1,dfn[y]);
}
void update_turn(int rt,int l,int r)
{
	if (l<=tree[rt].l && tree[rt].r<=r)
	{
		tree[rt].lazy*=-1;
		tree[rt].sum*=-1;
		tree[rt].maxx*=-1;tree[rt].minn*=-1;swap(tree[rt].maxx,tree[rt].minn);
		return;
	}
	pushdown(rt);
	int mid=(tree[rt].l+tree[rt].r) >> 1;
	if (l<=mid) update_turn(lson,l,r);
	if (r>mid) update_turn(rson,l,r);
	pushup(rt);
}
  • 单点覆盖
void update(int rt,int pos,int val)
{
	if (tree[rt].l == tree[rt].r && tree[rt].l == pos)
	{
		tree[rt].sum=tree[rt].maxx=tree[rt].minn=val;
		return;
	}
	pushdown(rt);
	int mid=(tree[rt].l+tree[rt].r) >> 1;
	if (pos<=mid) update(lson,pos,val);
	else update(rson,pos,val);
	pushup(rt);
}
  • 查询套餐
int query(int rt,int l,int r)
{
	int res=0;
	if(l>r) return res;
	if (l<=tree[rt].l && tree[rt].r<=r) return tree[rt].sum;
	pushdown(rt);
	int mid=(tree[rt].l+tree[rt].r) >> 1;
	if (l<=mid) res+=query(lson,l,r);
	if (r>mid) res+=query(rson,l,r);
	return res;
}
int query_maxx(int rt,int l,int r)
{
	int res=-0x3f3f3f3f;
	if(l>r) return res;
	if (l<=tree[rt].l && tree[rt].r<=r) return tree[rt].maxx;
	pushdown(rt);
	int mid=(tree[rt].l+tree[rt].r) >> 1;
	if (l<=mid) res=max(res,query_maxx(lson,l,r));
	if (r>mid) res=max(res,query_maxx(rson,l,r));
	return res;
}int query_minn(int rt,int l,int r)
{
	int res=0x3f3f3f3f;
	if(l>r) return res;
	if (l<=tree[rt].l && tree[rt].r<=r) return tree[rt].minn;
	pushdown(rt);
	int mid=(tree[rt].l+tree[rt].r) >> 1;
	if (l<=mid) res=min(res,query_minn(lson,l,r));
	if (r>mid) res=min(res,query_minn(rson,l,r));
	return res;
}
int query1(int x,int y)
{
	int res=0;
	while (top[x]!=top[y])
	{
		if (dep[top[x]]<dep[top[y]]) swap(x,y);
		res+=query(1,dfn[top[x]],dfn[x]);
		x=fa[top[x]];
	}
	if (dep[x]>dep[y]) swap(x,y);
	res+=query(1,dfn[x]+1,dfn[y]);
	return res;
}
int query2(int x,int y)
{
	int res=-0x3f3f3f3f;
	while (top[x]!=top[y])
	{
		if (dep[top[x]]<dep[top[y]]) swap(x,y);
		res=max(res,query_maxx(1,dfn[top[x]],dfn[x]));
		x=fa[top[x]];
	}
	if (dep[x]>dep[y]) swap(x,y);
	res=max(res,query_maxx(1,dfn[x]+1,dfn[y]));
	return res;
}
int query3(int x,int y)
{
	int res=0x3f3f3f3f;
	while (top[x]!=top[y])
	{
		if (dep[top[x]]<dep[top[y]]) swap(x,y);
		res=min(res,query_minn(1,dfn[top[x]],dfn[x]));
		x=fa[top[x]];
	}
	if (dep[x]>dep[y]) swap(x,y);
	res=min(res,query_minn(1,dfn[x]+1,dfn[y]));
	return res;
}

总代码

238行码量非常少

#include<bits/stdc++.h>
#define endl '\n'
#define Honkai ios::sync_with_stdio(0);
#define StarRail cin.tie(0);cout.tie(0);
#define lson (rt<<1)
#define rson (rt<<1|1)
using namespace std;
constexpr int maxn=1e6+10;
int n,m,a[maxn];
int fa[maxn],dep[maxn],siz[maxn],son[maxn],top[maxn];
int dfn[maxn],rnk[maxn],cnt;
struct _ {int l,r,sum,minn,maxx,lazy=1;}tree[maxn<<2];
int h[maxn],to[maxn],nxt[maxn],tot,w[maxn];
pair<int,int> path[maxn];
void add(int x,int y,int z) {tot++;to[tot]=y;w[tot]=z;nxt[tot]=h[x];h[x]=tot;}
void dfs1(int x)
{
	son[x]=-1;siz[x]=1;
	for (int i=h[x];i;i=nxt[i])
	{
		int y=to[i];
		if (dep[y]) continue;
		a[y]=w[i];
		dep[y]=dep[x]+1;
		fa[y]=x;
		dfs1(y);
		siz[x]+=siz[y];
		if (son[x] == -1 || siz[y]>siz[son[x]]) son[x]=y;
	}
}
void dfs2(int x,int t)
{
	top[x]=t;
	cnt++;
	dfn[x]=cnt;rnk[cnt]=x;
	if (son[x] == -1) return;
	dfs2(son[x],t);
	for (int i=h[x];i;i=nxt[i])
	{
		int y=to[i];
		if (y == son[x] || y == fa[x]) continue;
		dfs2(y,y);
	}
}
void pushup(int rt)
{
	tree[rt].sum=tree[lson].sum+tree[rson].sum;
	tree[rt].maxx=max(tree[lson].maxx,tree[rson].maxx);
	tree[rt].minn=min(tree[lson].minn,tree[rson].minn);
}
void pushdown(int rt)
{
	if (tree[rt].lazy == -1)
	{
		tree[rt].lazy=1;
		tree[lson].lazy*=-1;tree[rson].lazy*=-1;
		tree[lson].sum*=-1;tree[rson].sum*=-1;
		tree[lson].maxx*=-1;tree[lson].minn*=-1;swap(tree[lson].maxx,tree[lson].minn);
		tree[rson].maxx*=-1;tree[rson].minn*=-1;swap(tree[rson].maxx,tree[rson].minn);
	}
}
void build(int rt,int l,int r)
{
	tree[rt].l=l;tree[rt].r=r;
	if (l == r) {tree[rt].sum=tree[rt].maxx=tree[rt].minn=a[rnk[l]];return;}
	int mid=(l+r) >> 1;
	build(lson,l,mid);build(rson,mid+1,r);
	pushup(rt);
}
void update_turn(int rt,int l,int r)
{
	if (l<=tree[rt].l && tree[rt].r<=r)
	{
		tree[rt].lazy*=-1;
		tree[rt].sum*=-1;
		tree[rt].maxx*=-1;tree[rt].minn*=-1;swap(tree[rt].maxx,tree[rt].minn);
		return;
	}
	pushdown(rt);
	int mid=(tree[rt].l+tree[rt].r) >> 1;
	if (l<=mid) update_turn(lson,l,r);
	if (r>mid) update_turn(rson,l,r);
	pushup(rt);
}
void update(int rt,int pos,int val)
{
	if (tree[rt].l == tree[rt].r && tree[rt].l == pos)
	{
		tree[rt].sum=tree[rt].maxx=tree[rt].minn=val;
		return;
	}
	pushdown(rt);
	int mid=(tree[rt].l+tree[rt].r) >> 1;
	if (pos<=mid) update(lson,pos,val);
	else update(rson,pos,val);
	pushup(rt);
}
int query(int rt,int l,int r)
{
	int res=0;
	if(l>r) return res;
	if (l<=tree[rt].l && tree[rt].r<=r) return tree[rt].sum;
	pushdown(rt);
	int mid=(tree[rt].l+tree[rt].r) >> 1;
	if (l<=mid) res+=query(lson,l,r);
	if (r>mid) res+=query(rson,l,r);
	return res;
}
int query_maxx(int rt,int l,int r)
{
	int res=-0x3f3f3f3f;
	if(l>r) return res;
	if (l<=tree[rt].l && tree[rt].r<=r) return tree[rt].maxx;
	pushdown(rt);
	int mid=(tree[rt].l+tree[rt].r) >> 1;
	if (l<=mid) res=max(res,query_maxx(lson,l,r));
	if (r>mid) res=max(res,query_maxx(rson,l,r));
	return res;
}int query_minn(int rt,int l,int r)
{
	int res=0x3f3f3f3f;
	if(l>r) return res;
	if (l<=tree[rt].l && tree[rt].r<=r) return tree[rt].minn;
	pushdown(rt);
	int mid=(tree[rt].l+tree[rt].r) >> 1;
	if (l<=mid) res=min(res,query_minn(lson,l,r));
	if (r>mid) res=min(res,query_minn(rson,l,r));
	return res;
}
int query1(int x,int y)
{
	int res=0;
	while (top[x]!=top[y])
	{
		if (dep[top[x]]<dep[top[y]]) swap(x,y);
		res+=query(1,dfn[top[x]],dfn[x]);
		x=fa[top[x]];
	}
	if (dep[x]>dep[y]) swap(x,y);
	res+=query(1,dfn[x]+1,dfn[y]);
	return res;
}
int query2(int x,int y)
{
	int res=-0x3f3f3f3f;
	while (top[x]!=top[y])
	{
		if (dep[top[x]]<dep[top[y]]) swap(x,y);
		res=max(res,query_maxx(1,dfn[top[x]],dfn[x]));
		x=fa[top[x]];
	}
	if (dep[x]>dep[y]) swap(x,y);
	res=max(res,query_maxx(1,dfn[x]+1,dfn[y]));
	return res;
}
int query3(int x,int y)
{
	int res=0x3f3f3f3f;
	while (top[x]!=top[y])
	{
		if (dep[top[x]]<dep[top[y]]) swap(x,y);
		res=min(res,query_minn(1,dfn[top[x]],dfn[x]));
		x=fa[top[x]];
	}
	if (dep[x]>dep[y]) swap(x,y);
	res=min(res,query_minn(1,dfn[x]+1,dfn[y]));
	return res;
}
void add1(int x,int y)
{
	while (top[x]!=top[y])
	{
		if (dep[top[x]]<dep[top[y]]) swap(x,y);
		update_turn(1,dfn[top[x]],dfn[x]);
		x=fa[top[x]];
	}
	if(dep[x]>dep[y]) swap(x,y);
	update_turn(1,dfn[x]+1,dfn[y]);
}
int main()
{
	Honkai StarRail
	cin >> n;
	for (int i=1;i<n;i++)
	{
		int x,y,z;
		cin >> x >> y >> z;
		x++;y++;
		path[i]={x,y};
		add(x,y,z);add(y,x,z);
	}
	dep[1]=1;
	dfs1(1);dfs2(1,1);
	build(1,1,cnt);
	cin >> m;
	while (m--)
	{
		string s;
		cin >> s;
		if (s == "C")
		{
			int x,y;
			cin >> x >> y;
			int u=path[x].first,v=path[x].second;
			if (fa[u]!=v) swap(u,v);
			update(1,dfn[u],y);
		}
		if (s == "N")
		{
			int x,y;
			cin >> x >> y;
			x++;y++;
			add1(x,y);
		}
		if (s == "SUM")
		{
			int x,y;
			cin >> x >> y;
			x++;y++;
			cout << query1(x,y) << endl;
		}
		if (s == "MAX")
		{
			int x,y;
			cin >> x >> y;
			x++;y++;
			cout << query2(x,y) << endl;
		}
		if (s == "MIN")
		{
			int x,y;
			cin >> x >> y;
			x++;y++;
			cout << query3(x,y) << endl;
		}
	}
	return 0;
}

附:样例图一张

graph (3)

鸣谢

wang7979
zyz

posted @ 2026-06-06 13:49  msjing  阅读(6)  评论(0)    收藏  举报