1. 程式人生 > >JZOJ5463. 【NOIP2017提高A組衝刺11.8】證書

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; }