P1505 [國家集訓隊]旅遊 (樹鏈剖分)

Tuilot發表於2020-10-09

傳送門
很明顯是樹鏈剖分,因為是邊權,所以將每個邊權給深度大的那個點可以了,根節點不用賦值,要求最大值和最小值,所以線段樹不包含根節點。因為點是從0編號的,所以父節點和重兒子陣列要初始化。

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int N=200010,inf=0x3f3f3f3f;
int n,m,a[N],b[N],c[N],h[N],e[N<<1],ne[N<<1],w[N<<1],idx,col[N];
void add(int a,int b,int c)
{
	e[idx]=b;ne[idx]=h[a];w[idx]=c;h[a]=idx++;
}
struct segtree
{
	struct node
	{
		int l,r,sum,maxx,minn,lzy;
	}tr[N<<2];
	void pushup(node &rt,node &l,node &r)
	{
		rt.sum=l.sum+r.sum;
		rt.maxx=max(l.maxx,r.maxx);
		rt.minn=min(l.minn,r.minn);
	}
	void pushdown(node &rt,node &l,node &r)
	{
		if(rt.lzy&1)
		{
			l.sum*=-1; l.maxx^=l.minn^=l.maxx^=l.minn;l.maxx*=-1;l.minn*=-1;
			r.sum*=-1; r.maxx^=r.minn^=r.maxx^=r.minn;r.maxx*=-1;r.minn*=-1;
			l.lzy+=rt.lzy;
			r.lzy+=rt.lzy;
		}
		rt.lzy=0;
	}
	void build(int rt,int l,int r)
	{
		if(l==r) tr[rt]={l,r,col[l],col[l],col[l],0};
		else 
		{
			int mid=l+r>>1;
			tr[rt]={l,r};
			build(rt<<1,l,mid);
			build(rt<<1|1,mid+1,r);
			pushup(tr[rt],tr[rt<<1],tr[rt<<1|1]);
		}
	}
	void updata(int rt,int l,int r,int d,int f)
	{
		if(l<=tr[rt].l&&r>=tr[rt].r)
		{
			if(f==1)//取相反數
			{
				tr[rt].sum*=-1;
				tr[rt].maxx^=tr[rt].minn^=tr[rt].maxx^=tr[rt].minn;
				tr[rt].minn*=-1;tr[rt].maxx*=-1;
				tr[rt].lzy++;
			}
			else tr[rt].maxx=tr[rt].sum=tr[rt].minn=d;//邊權賦值,單點更新
			return ;
		}
		int mid=tr[rt].l+tr[rt].r>>1;
		pushdown(tr[rt],tr[rt<<1],tr[rt<<1|1]);
		if(l<=mid) updata(rt<<1,l,r,d,f);
		if(r>mid) updata(rt<<1|1,l,r,d,f);
		pushup(tr[rt],tr[rt<<1],tr[rt<<1|1]);
		return ;
	}
	node query(int rt,int l,int r)
	{
		if(l<=tr[rt].l&&r>=tr[rt].r) return tr[rt];
		int mid=tr[rt].l+tr[rt].r>>1;
		pushdown(tr[rt],tr[rt<<1],tr[rt<<1|1]);
		if(r<=mid) return query(rt<<1,l,r);
		if(l>mid) return query(rt<<1|1,l,r);
		node ans,left,right;
		left=query(rt<<1,l,r);
		right=query(rt<<1|1,l,r);
		pushup(ans,left,right);
		return ans;
	}
}tree;
struct shupo
{
	int top[N],dfn[N],son[N],dep[N],sz[N],fa[N],cnt;
	void dfs1(int u)
	{
		sz[u]=1;
		for(int i=h[u];i!=-1;i=ne[i])
		{
			int v=e[i];
			if(v==fa[u]) continue;
			dep[v]=dep[u]+1;
			fa[v]=u;
			dfs1(v);
			sz[u]+=sz[v];
			if(son[u]==-1) son[u]=v;
			else if(sz[v]>sz[son[u]]) son[u]=v;
		}
	}
	void dfs2(int u,int t,int c)
	{
		dfn[u]=++cnt;
		col[cnt]=c;
		top[u]=t;
		for(int i=h[u];i!=-1;i=ne[i])
			if(e[i]==son[u])
		 		dfs2(son[u],t,w[i]);
		for(int i=h[u];i!=-1;i=ne[i])
		{
			int v=e[i];
			if(v==son[u]||v==fa[u]) continue;
			dfs2(v,v,w[i]);
		}
	}
	void updata_ed(int u,int d)
	{
		if(dep[a[u]]>dep[b[u]]) a[u]^=b[u]^=a[u]^=b[u];  
		tree.updata(1,dfn[b[u]],dfn[b[u]],d,0);//a[u],b[u]的時間戳不相鄰!!
	}
	void updata_mem(int x,int y)
	{
		while(top[x]!=top[y])
		{
			if(dep[top[x]]>dep[top[y]]) x^=y^=x^=y;//swap
			tree.updata(1,dfn[top[y]],dfn[y],0,1);
			y=fa[top[y]];
		}
		if(dep[x]>dep[y]) x^=y^=x^=y;
		if(dfn[x]+1<=dfn[y]) tree.updata(1,dfn[x]+1,dfn[y],0,1);//同一條鏈的時候深度高的那個點表示的邊權不在要更新的路徑上,下同
		return ;
	}
	int query_sum(int x,int y)
	{
		int ans=0;
		while(top[x]!=top[y])
		{
			if(dep[top[x]]>dep[top[y]]) x^=y^=x^=y;
			ans+=tree.query(1,dfn[top[y]],dfn[y]).sum;
			y=fa[top[y]];
		}
		if(dep[x]>dep[y]) x^=y^=x^=y;
		if(dfn[x]+1<=dfn[y]) ans+=tree.query(1,dfn[x]+1,dfn[y]).sum;
		return ans;
	}
	int query_max(int x,int y)
	{
		int ans=-inf;
		while(top[x]!=top[y])
		{
			if(dep[top[x]]>dep[top[y]]) x^=y^=x^=y;
			ans=max(ans,tree.query(1,dfn[top[y]],dfn[y]).maxx);
			y=fa[top[y]];
		}
		if(dep[x]>dep[y]) x^=y^=x^=y;
		if(dfn[x]+1<=dfn[y]) ans=max(ans,tree.query(1,dfn[x]+1,dfn[y]).maxx);
		return ans;
	}
	int query_min(int x,int y)
	{
		int ans=inf;
		while(top[x]!=top[y])
		{
			if(dep[top[x]]>dep[top[y]]) x^=y^=x^=y;
			ans=min(ans,tree.query(1,dfn[top[y]],dfn[y]).minn);
			y=fa[top[y]];
		}
		if(dep[x]>dep[y]) x^=y^=x^=y;
		if(dfn[x]+1<=dfn[y]) ans=min(ans,tree.query(1,dfn[x]+1,dfn[y]).minn);
		return ans;
	}
}T;

int main()
{
	memset(h,-1,sizeof h);
	memset(T.son,-1,sizeof T.son);
	memset(T.fa,-1,sizeof T.fa);
	scanf("%d",&n);
	for(int i=1;i<n;i++)
	{
		scanf("%d%d%d",a+i,b+i,c+i);
		add(a[i],b[i],c[i]);
		add(b[i],a[i],c[i]);
	}
	T.dfs1(0);
	T.dfs2(0,0,0);
	tree.build(1,2,n);
	
	scanf("%d",&m);
	char op[5];
	int x,y;
	while(m--)
	{
		scanf("%s%d%d",op,&x,&y);
		if(*op=='C') T.updata_ed(x,y);
		else if(*op=='N')	T.updata_mem(x,y);
		else if(*op=='S') printf("%d\n",T.query_sum(x,y));
		else if(op[1]=='A') printf("%d\n",T.query_max(x,y));
		else printf("%d\n",T.query_min(x,y));
	}
	return 0;
}

相關文章