jzoj5463【NOIP2017提高A组冲刺11.8】证书

题目

Time Limits: 3000 ms Memory Limits: 524288 KB

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

题解

如果用线段树合并的话是一道十分裸的题目,只要在两个儿子+1,lca及其父亲-1即可
主要是没有打过线段树合并
其实直接强行合并就好了,不需要启发式

贴代码

#include
#include
#include
#include
#include
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fo1(i,b,a) for(i=b;i>=a;i--)
using namespace std;

const int maxn=1e5+5;

struct P{
    int x,y,z;
}a[maxn];
int tree[maxn*30][5];
int fi[maxn],ne[maxn*2],dui[maxn*2],qc[maxn],ans[maxn];
int fi1[maxn],ne1[maxn*8],dui1[maxn*4],dui2[maxn*8],qc1[maxn];
int de[maxn],f[maxn][20],root[maxn];
int d[maxn];
int i,j,k,l,m,n,x,y,z,now,la,now1,p,o;

void add(int x,int y){
    if (fi[x]==0) fi[x]=++now; else ne[qc[x]]=++now;
    dui[now]=y; qc[x]=now;
}
void add1(int x,int y,int z){
    if (fi1[x]==0) fi1[x]=++now1; else ne1[qc1[x]]=++now1;
    dui1[now1]=y; qc1[x]=now1; dui2[now1]=z;
}
int cmp(P x,P y){
    return x.z<y.z;
}
void gef(){
    fo(j,1,16)
        fo(i,1,n) f[i][j]=f[f[i][j-1]][j-1];
}
int lca(int x,int y){
    int i;
    if (de[x]y]){
        z=x; x=y; y=z;
    }
    fo1(i,16,0) if (de[x]-(1<=de[y]) x=f[x][i];
    fo1(i,16,0) if (f[x][i]!=f[y][i]){
        x=f[x][i]; y=f[y][i];
    }
    if (x!=y) x=f[x][0];
    return x;
}
void dfs(int x){
    int i=fi[x];
    while (i){
        if (de[dui[i]]!=0){
            i=ne[i];
            continue;
        }
        de[dui[i]]=de[x]+1;
        f[dui[i]][0]=x;
        dfs(dui[i]);
        i=ne[i];
    }
}
void bing(int v,int x,int l,int r){
    if (l==r) tree[v][3]+=tree[x][3]; else{
        int mid=(l+r)/2;
        if (tree[v][1]==0 && tree[x][1]>0) tree[v][1]=tree[x][1]; else
        if (tree[v][1]>0 && tree[x][1]>0) bing(tree[v][1],tree[x][1],l,mid);
        if (tree[v][2]==0 && tree[x][2]>0) tree[v][2]=tree[x][2]; else
        if (tree[v][2]>0 && tree[x][2]>0) bing(tree[v][2],tree[x][2],mid+1,r);
        tree[v][3]=max(tree[tree[v][1]][3],tree[tree[v][2]][3]);
    }
}
void change(int v,int l,int r,int x,int z){
    if (l==r) tree[v][3]=tree[v][3]+z; else{
        int mid=(l+r)/2;
        if (x<=mid){
            if (tree[v][1]==0) tree[v][1]=++p;
            change(tree[v][1],l,mid,x,z);
        } else{
            if (tree[v][2]==0) tree[v][2]=++p;
            change(tree[v][2],mid+1,r,x,z);
        }
        tree[v][3]=max(tree[tree[v][1]][3],tree[tree[v][2]][3]);
    }
}
void find(int v,int l,int r){
    if (l==r){
        if (tree[v][3]) ans[o]=l;   
    }else{
        int mid=(l+r)/2;
        if (tree[tree[v][1]][3]>=tree[tree[v][2]][3]) 
        find(tree[v][1],l,mid); else find(tree[v][2],mid+1,r);
    }
}
void dfs1(int x){
    int i=fi[x];
    while (i){
        if (f[x][0]==dui[i]){
            i=ne[i];
            continue;
        }
        dfs1(dui[i]);
        i=ne[i];
    }
    i=fi[x];
    while (i){
        if (f[x][0]==dui[i]){
            i=ne[i];
            continue;
        }
        if (root[x]==0) root[x]=root[dui[i]]; else bing(root[x],root[dui[i]],1,now);
        i=ne[i];
    }
    if (root[x]==0) root[x]=++p;
    i=fi1[x];
    while (i){
        change(root[x],1,now,dui1[i],dui2[i]);
        i=ne1[i];
    }
    o=x;
    find(root[x],1,now);
}
int main(){
    freopen("certif.in","r",stdin);
    freopen("certif.out","w",stdout);
    scanf("%d%d",&n,&m);
    fo(i,1,n-1){
        scanf("%d%d",&x,&y);
        add(x,y); add(y,x);
    }
    de[1]=1;
    dfs(1);
    gef();
    fo(i,1,m) scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
    sort(a+1,a+m+1,cmp);
    now=0;
    fo(i,1,m) if (a[i].z!=la){
        la=a[i].z;
        d[++now]=a[i].z; a[i].z=now;
    } else{
        la=a[i].z;
        a[i].z=now;
    }
    fo(i,1,m){
        x=a[i].x; y=a[i].y; z=lca(x,y);
        add1(x,a[i].z,1); add1(y,a[i].z,1);
        add1(z,a[i].z,-1); add1(f[z][0],a[i].z,-1);
    }
    p=0;
    dfs1(1);
    fo(i,1,n) printf("%d\n",d[ans[i]]);
    return 0;
}

你可能感兴趣的:(线段树合并)