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的树链剖分就做完啦!
喜欢可以三连哦