[Ipsc2009]Let there be rainbows!

Description

HY Star是一个处处充满和谐,人民安居乐业的星球,但是HY Star却没有被评上宇宙文明星球,很大程度上是因为 星球的形象问题。HY Star由N个国家组成,并且在一些国家之间修建了道路以方便交流。由于HY Star是一个和谐的 星球,因此任意两个国家有且仅有一条路径连接它们。而让HY Star备受诟病的便是他们修建的道路的颜色过于单 调,全部是使用灰色。经过了一年又一年的宇宙文明星球的落选,HY Star的首领BOSS决定改变这种状况,但是他并 不想重新修建新的道路,因为这太耗费人力物力,他决定将已有的道路重新涂色。在各方的讨论下,BOSS决定将现 有的道路涂成彩虹的颜色。每一天,BOSS都会选择两个国家A,B和一种颜色C,并将A,B之间颜色不是C的道路的颜色 都涂成C。BOSS将涂色的具体计划预先告诉了颜料厂,以便有充足的时间来准备颜料。作为颜料厂的负责人,你需要 知道每种颜色被使用了多少次。

Format

Input

第一行,一个整数N,表示HY Star的国家的编号是1~N。

下面若干行,每行两个数A,B,表示A,B之间有道路直接连接。

下面一行,一个整数Q,表示计划的持续天数。

下面Q行,每行三个正整数,S,T,C(1<=S,T<=N,1<=C<=7),表示将S,T之间颜色不是C的道路的颜色都涂成C。

1 < = N,Q < = 200000

Output

共包含7行,第i行包含一个整数,表示颜色i的使用次数。

Samples

输入数据 1

4
1 2
2 3
3 4
3
1 4 1
2 4 2
1 3 1

输出数据 1

4
2
0
0
0
0
0

Solution:

这道题应该是一道树链剖分的板子题

两个经典的DFS+线段树求解,详细看TLE代码:

Code:

#include<bits/stdc++.h>
using namespace std;
#define ls p<<1
#define rs p<<1|1
#define ll long long
const int N=2e5+10;
int n,q;
int pre[4*N],son[4*N],now[4*N],tot;
int dis[N];
void put(int x,int y) {
	pre[++tot]=now[x];
	now[x]=tot;
	son[tot]=y;
}
int dep[N],siz[N],fa[N];
int hs[N];
void dfs1(int x,int f) {//找重边
	fa[x]=f;
	dep[x]=dep[f]+1;
	siz[x]=1;
	for(int i=now[x]; i; i=pre[i])
		if(son[i]!=f) {
			dfs1(son[i],x);
			siz[x]+=siz[son[i]];
			if(siz[hs[x]]<siz[son[i]])
				hs[x]=son[i];
		}
}
int top[N],dfn[N],rnk[N],cnt;
void dfs2(int x,int f) {//连重边成重链
	top[x]=f;
	dfn[x]=++cnt;
	rnk[cnt]=x;
	if(hs[x]) dfs2(hs[x],f);
	for(int i=now[x]; i; i=pre[i])
		if(hs[x]!=son[i]&&fa[x]!=son[i])
			dfs2(son[i],son[i]);
}
int sum[4*N];
int lazy[4*N];
int ans[10];
void update(int p) {
	sum[p]=sum[ls]+sum[rs];
}
void build(int p,int l,int r) {
	if(l==r) {
		sum[p]=0;
		return ;
	}
	int mid=l+r>>1;
	build(ls,l,mid);
	build(rs,mid+1,r);
	update(p);
}
void change(int p,int l,int r,int x,int y,int z) {
	if(x<=l&&r<=y&&l==r) {//可以优化
		if(sum[p]!=z) ans[z]++;
		sum[p]=z;
		return ;
	}
	int mid=l+r>>1;
	if(x<=mid) change(ls,l,mid,x,y,z);
	if(y>mid) change(rs,mid+1,r,x,y,z);
	update(p);
}
void qchange(int x,int y,int z) {//树链剖分
	while(top[x]!=top[y]) {
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		change(1,1,n,dfn[top[x]],dfn[x],z);
		x=fa[top[x]];
	}
	if(dfn[x]>dfn[y]) swap(x,y);
	if(x!=y) change(1,1,n,dfn[x]+1,dfn[y],z);
}
int x,y,z;
string str;
int main() {
	cin>>n;
	for(int i=1; i<n; i++) {
		cin>>x>>y;
		put(x,y);
		put(y,x);
	}
	dep[1]=1;
	fa[1]=1;
	dfs1(1,0);
	dfs2(1,1);
	build(1,1,n);
	cin>>q;
	while(q--) {
		cin>>x>>y>>z;
		qchange(x,y,z);
	}
	for(int i=1; i<=7; i++) cout<<ans[i]<<endl;

	return 0;
}

这个代码是TLE了,但它可以优化,加上一个lazy标记即可

#include<bits/stdc++.h>
using namespace std;
#define ls p<<1
#define rs p<<1|1
#define ll long long
const int N=2e5+10;
int n,q;
int pre[4*N],son[4*N],now[4*N],tot;
int dis[N];
void put(int x,int y) {
	pre[++tot]=now[x];
	now[x]=tot;
	son[tot]=y;
}
int dep[N],siz[N],fa[N];
int hs[N];
void dfs1(int x,int f) {
	fa[x]=f;
	dep[x]=dep[f]+1;
	siz[x]=1;
	for(int i=now[x]; i; i=pre[i])
		if(son[i]!=f) {
			dfs1(son[i],x);
			siz[x]+=siz[son[i]];
			if(siz[hs[x]]<siz[son[i]])
				hs[x]=son[i];
		}
}
int top[N],dfn[N],rnk[N],cnt;
void dfs2(int x,int f) {
	top[x]=f;
	dfn[x]=++cnt;
	rnk[cnt]=x;
	if(hs[x]) dfs2(hs[x],f);
	for(int i=now[x]; i; i=pre[i])
		if(hs[x]!=son[i]&&fa[x]!=son[i])
			dfs2(son[i],son[i]);
}
int sum[4*N][10];//sum[p][i]表示以p为根的子树中,颜色i有几条
int lazy[4*N];
int ans[10];
void update(int p) {
	for(int i=0; i<=7; i++)
		sum[p][i]=sum[ls][i]+sum[rs][i];
}
void build(int p,int l,int r) {
	if(l==r) {
		sum[p][0]=1;
		return ;
	}
	int mid=l+r>>1;
	build(ls,l,mid);
	build(rs,mid+1,r);
	update(p);
}
void push(int p,int l,int r) {//优化
	if(lazy[p]) {
		int mid=l+r>>1;
		for(int i=0; i<=7; i++)
			if(i!=lazy[p])
				sum[ls][i]=sum[rs][i]=0;
		sum[ls][lazy[p]]=mid-l+1;
		sum[rs][lazy[p]]=r-mid;
		lazy[ls]=lazy[rs]=lazy[p];
		lazy[p]=0;
	}
}
void change(int p,int l,int r,int x,int y,int z) {
	if(x<=l&&r<=y) {
		for(int i=0; i<=7; i++)
			if(i!=z)
				ans[z]+=sum[p][i],sum[p][i]=0;
		sum[p][z]=r-l+1;
		lazy[p]=z;
		return ;
	}
	push(p,l,r);
	int mid=l+r>>1;
	if(x<=mid) change(ls,l,mid,x,y,z);
	if(y>mid) change(rs,mid+1,r,x,y,z);
	update(p);
}
void qchange(int x,int y,int z) {
	while(top[x]!=top[y]) {
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		change(1,1,n,dfn[top[x]],dfn[x],z);
		x=fa[top[x]];
	}
	if(dfn[x]>dfn[y]) swap(x,y);
	if(x!=y) change(1,1,n,dfn[x]+1,dfn[y],z);
}
int x,y,z;
string str;
int main() {
	cin>>n;
	for(int i=1; i<n; i++) {
		cin>>x>>y;
		put(x,y);
		put(y,x);
	}
	dep[1]=1;
	fa[1]=1;
	dfs1(1,0);
	dfs2(1,1);
	build(1,1,n);
	cin>>q;
	while(q--) {
		cin>>x>>y>>z;
		qchange(x,y,z);
	}
	for(int i=1; i<=7; i++) cout<<ans[i]<<endl;

	return 0;
}

这道sb的树链剖分就做完啦!

喜欢可以三连哦

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值