Description
Pulumi生活在P城的角落,而他的朋友们gjdy,oyski,tutuwai等等生活在P城的靠中心位置。
P城很大,但它拥有优秀的城市结构,同时P城重视文化教育的发展,P城共有n个学校,校与校之间共建立了n-1条交通线路,且两所学校之间存在唯一的连通路径。
P城常常举行各种类型的评比活动,为了节约资金,最终将给某一条路径上的所有学校颁发证书。为了便于描述我们记一次评比活动的结果为(ui,vi,zi)表示路径(ui,vi)上的所有学校获得一个类型为zi的证书。
一个学校若为Zmax类型的学校,则表示它在Zmax类型下的证书数量最多(如果有相同数量的类型,取类型标号最小一个)。
Pulumi收集了本年度所有的评比活动结果,共m次。他很感兴趣所有学校的类型,以了解他朋友们学校的状况,现在他忙于出题,把这个任务交给了你。
Input
第一行,两个整数n,m,如题中所述。
下接n-1行,每行两个整数u,v,表示标号u和v的学校之间有一条直接相连的路。
下接m行,每行三个整数u,v,z,表示一次结果为(u,v,z)的评比活动。
Output
共n行,第i行,一个整数zi,表示标号为i的学校类型为zi。
Sample Input
5 3
1 2
3 1
3 4
5 3
2 3 3
1 5 2
3 3 3
Sample Output
2
3
3
0
2
Data Constraint
对于30%的数据1<=N<=1000,1<=M<=1000
另外在30%的数据满足i-1与i之间有一条直接相连的路
对于100%的数据1<=N<=100000,0<=M<=100000,1<=zi<=10^9
题解
树上的路径修改?LCT?
虽然可以用LCT做,但是还有别的更好的方法。
对于一个点,
如何求出最小而且次数最多的?
可以用线段树,
然而每一个点都开一棵线段树?
空间估计不会允许。
可以用可持久化。
树上给一条路径加1,
就是在两个点+1,lca-1,lac的父亲-1。
类似的,先在这些对于的线段树里面对应的位置+1或者-1
然后线段树合并,
将全部儿子的线段树合并到这个点,
code
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#define N 100003
#define M ((l+r)>>1)
#define ll long long
#define ls t[x].l
#define rs t[x].r
#define lt t[y].l
#define rt t[y].r
using namespace std;
char ch;
void read(int& n)
{
n=0;
for(ch=getchar();ch<'0'||ch>'9';ch=getchar());
for(;'0'<=ch && ch<='9';n=(n<<3)+(n<<1)+ch-48,ch=getchar());
}
struct node
{
int x,y,z;
}a[N];
bool cmp(node a,node b)
{
return a.z<b.z;
}
void write(int x)
{
if(x>9)write(x/10);
putchar(x%10+48);
}
struct tree{
int l,r,mx,w,s;
}t[8000003];
int n,m,x,y,ans[N],w[N],ops,opx;
int nxt[N*2],to[N*2],b[N],tot;
int deep[N],f[18][N],L;
void ins(int x,int y)
{
nxt[++tot]=b[x];
to[tot]=y;
b[x]=tot;
}
int lca(int x,int y)
{
if(deep[x]>deep[y])swap(x,y);
for(int j=16;j>=0;j--)
if(deep[x]<=deep[f[j][y]])y=f[j][y];
if(x==y)return x;
for(int j=16;j>=0;j--)
if(f[j][x]!=f[j][y])x=f[j][x],y=f[j][y];
return f[0][x];
}
void dfs(int x)
{
for(int i=b[x];i;i=nxt[i])
if(f[0][x]!=to[i])
{
f[0][to[i]]=x;
deep[to[i]]=deep[x]+1;
dfs(to[i]);
}
}
void updata(int x)
{
if(!ls)
{
t[x].mx=t[rs].mx;
t[x].w=t[rs].w;
return;
}
if(!rs)
{
t[x].mx=t[ls].mx;
t[x].w=t[ls].w;
return;
}
if(t[ls].mx>=t[rs].mx)
{
t[x].mx=t[ls].mx;
t[x].w=t[ls].w;
return;
}
else
{
t[x].mx=t[rs].mx;
t[x].w=t[rs].w;
return;
}
}
void add(int x,int l,int r)
{
if(l==r)
{
t[x].s+=opx;
t[x].mx=t[x].s;
t[x].w=l;
return;
}
int m=M;
if(ops<=m)
{
if(!ls)ls=++tot;
add(ls,l,m);
}
else
{
if(!rs)rs=++tot;
add(rs,m+1,r);
}
updata(x);
}
void hb(int x,int y,int l,int r)
{
if(l==r)
{
t[x].s+=t[y].s;
t[x].mx=t[x].s;
if(t[x].mx>0)t[x].w=l;else t[x].w=0;
return;
}
if(lt)
{
if(!ls)ls=lt;else hb(ls,lt,l,M);
}
if(rt)
{
if(!rs)rs=rt;else hb(rs,rt,M+1,r);
}
updata(x);
}
void dfs1(int x)
{
for(int i=b[x];i;i=nxt[i])
if(f[0][x]!=to[i])
{
dfs1(to[i]);
hb(x+1,to[i]+1,1,w[0]);
}
ans[x]=t[x+1].w;
}
int main()
{
freopen("certif.in","r",stdin);
freopen("certif.out","w",stdout);
read(n);read(m);
for(int i=1;i<n;i++)
read(x),read(y),ins(x,y),ins(y,x);
for(int i=1;i<=m;i++)
read(a[i].x),read(a[i].y),read(a[i].z);
sort(a+1,a+1+m,cmp);
w[1]=a[1].z;deep[1]=w[0]=1;
for(int i=1;i<=m;i++)
{
if(a[i].z!=w[w[0]])w[++w[0]]=a[i].z;
a[i].z=w[0];
}
dfs(1);
for(int j=1;j<=16;j++)
for(int i=1;i<=n;i++)
f[j][i]=f[j-1][f[j-1][i]];
tot=n+1;
for(int i=1;i<=m;i++)
{
ops=a[i].z;opx=1;
x=a[i].x;y=a[i].y;
L=lca(x,y);
add(x+1,1,w[0]);
add(y+1,1,w[0]);
opx=-1;
add(f[0][L]+1,1,w[0]);
add(L+1,1,w[0]);
}
dfs1(1);
for(int i=1;i<=n;i++)
write(ans[i]?w[ans[i]]:0),putchar('\n');
return 0;
}