JZOJ5463. 【NOIP2017提高A組衝刺11.8】證書
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;
}