Luogu_P4556 雨天的尾巴【题解】树上差分 线段树合并

题面:https://www.luogu.com.cn/problem/P4556

对于在一条(x,y)路径上将z加1。

就可以树上差分。

x和y都是加1。lca是减1,lca的father也是减1。

但是由于又有很多种不一样的种类。

还需要每个点维护一个线段树。

合并的时候求哪个种类是max。

最后统计答案dfs。

思路简单,主要是代码长。 

代码如下:

#pragma-GCC-optimize("O2,Ofast,inline,unroll-all-loops,-ffast-math")
#pragma-GCC-target("avx,sse2,sse3,sse4,popcnt")
#include<bits/stdc++.h>
using namespace std;
const int maxn=100010;
int tt,n,m;
struct node{
    int nxt,to;
    #define nxt(x) e[x].nxt
    #define to(x) e[x].to
}e[maxn<<1];
int head[maxn],tot,dep[maxn],f[maxn][21],rt[maxn],num,cnt,X[maxn],Y[maxn],Z[maxn],val[maxn],ans[maxn];
inline void add(int x,int y){
    to(++tot)=y;
    nxt(tot)=head[x];head[x]=tot;
}
queue<int> q;
inline long read(){
    long x=0,f=1;char c=getchar();
    while(c>'9'||c<'0'){if(c=='-')f*=-1;c=getchar();}
    while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
    return x*f;
}
inline void bfs(){
    q.push(1);dep[1]=1;
    while(q.size()){
        int x=q.front();q.pop();
        for(int i=head[x];i;i=nxt(i)){
            int to=to(i);
            if(dep[to]) continue;
            dep[to]=dep[x]+1;
            f[to][0]=x;
            for(int j=1;j<=tt;j++)
                f[to][j]=f[f[to][j-1]][j-1];
            q.push(to);
        }
    }
}
inline int lca(int x,int y){
    if(dep[x]>dep[y]) swap(x,y);
    for(int i=tt;i>=0;i--)
        if(dep[f[y][i]] >= dep[x]) y=f[y][i];
    if(x==y) return x;
    for(int i=tt;i>=0;i--)
        if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    return f[x][0];
}
struct tree{
    int lc,rc,dt,tg;
}t[maxn*80];
void insert(int p,int l,int r,int vl,int d){
    if(l==r){
        t[p].dt+=d;
        t[p].tg=t[p].dt ? l : 0 ;
        return;
    }
    int mid=(l+r)>>1;
     if(vl<=mid){
         if(!t[p].lc) t[p].lc=++num;
         insert(t[p].lc,l,mid,vl,d);
     }else{
         if(!t[p].rc) t[p].rc=++num;
         insert(t[p].rc,mid+1,r,vl,d);
     }
     t[p].dt=max(t[t[p].lc].dt,t[t[p].rc].dt);
     t[p].tg=t[t[p].lc].dt>=t[t[p].rc].dt ? t[t[p].lc].tg : t[t[p].rc].tg;
}
int merge(int p,int q,int l,int r){
    if(!p) return q;
    if(!q) return p;
    if(l==r){
        t[p].dt+=t[q].dt;
        t[p].tg=t[p].dt ? l : 0;
        return p;
    }
    int mid=(l+r)>>1;
    t[p].lc=merge(t[p].lc,t[q].lc,l,mid);
    t[p].rc=merge(t[p].rc,t[q].rc,mid+1,r);
    t[p].dt=max(t[t[p].lc].dt,t[t[p].rc].dt);
    t[p].tg=t[t[p].lc].dt>=t[t[p].rc].dt ? t[t[p].lc].tg : t[t[p].rc].tg;
    return p;
}
void dfs(int x){
    for(int i=head[x];i;i=nxt(i)){
        int to=to(i);
        if(dep[to]<=dep[x]) continue;
        dfs(to);
        rt[x]=merge(rt[x],rt[to],1,cnt);
    }
    ans[x]=t[rt[x]].tg;
}
int main()
{
    n=read(),m=read();
    tt=(int)(log(n)/log(2))+1;
    for(int i=1;i<n;i++){
        int x,y;x=read();y=read();
        add(x,y);add(y,x);
    }
    bfs();
    for(int i=1;i<=n;i++) rt[i]=++num;
    for(int i=1;i<=m;i++){
        X[i]=read();Y[i]=read();Z[i]=read();
        val[i]=Z[i];
    }
    sort(val+1,val+1+m);
    cnt=unique(val+1,val+1+m)-val-1;
    for(int i=1;i<=m;i++){
        int x=X[i],y=Y[i];
        int z=lower_bound(val+1,val+1+cnt,Z[i])-val;
        int lc=lca(x,y);
        insert(rt[x],1,cnt,z,1);
        insert(rt[y],1,cnt,z,1);
        insert(rt[lc],1,cnt,z,-1);
        if(f[lc][0]) insert(rt[f[lc][0]],1,cnt,z,-1);
    }
    dfs(1);
    for(int i=1;i<=n;i++) printf("%d\n",val[ans[i]]);
    return 0;
}
扫描二维码关注公众号,回复: 7311244 查看本文章

猜你喜欢

转载自www.cnblogs.com/ChrisKKK/p/11544029.html
今日推荐