[BZOJ3307]雨天的尾巴:树上差分+树链剖分

分析:

又是一道本校OI组交流的(水)题,正解好像是线段树合并什么的,不过我用我的方法写了一下。
做过了天天爱跑步,这道题就非常简单了。
树链剖分后通过树剖dfs序模拟一遍dfs统计答案,统计时要用到一棵权值线段树。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <vector>

inline int read(){
    int x=0;char ch=getchar();
    while(ch<'0'||ch>'9') ch=getchar();
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x;
}

const int MAXN=100005;
int n,m,ecnt,head[MAXN];
int fa[MAXN],dep[MAXN],siz[MAXN],pc[MAXN],top[MAXN],id[MAXN],num[MAXN],tot;
int uu[MAXN],vv[MAXN],zz[MAXN],b[MAXN],Flect[MAXN];
int loc,k;
int ans[MAXN];
std::vector<int> v[MAXN],v1[MAXN],v2[MAXN];
struct Edge{
    int to,nxt;
}e[MAXN<<1];
struct Node{
    int z,maxn;
}a[MAXN<<2];

inline Node max(Node x,Node y){
    return x.maxn==y.maxn?(x.z<y.z?x:y):(x.maxn>y.maxn?x:y);
}

inline void add_edge(int bg,int ed){
    ecnt++;
    e[ecnt].to=ed;
    e[ecnt].nxt=head[bg];
    head[bg]=ecnt;
}

void dfs1(int x,int pre,int depth){
    fa[x]=pre;
    dep[x]=depth;
    siz[x]=1;
    int maxsiz=-1;
    for(int i=head[x];i;i=e[i].nxt){
        int ver=e[i].to;
        if(ver==pre) continue;
        dfs1(ver,x,depth+1);
        siz[x]+=siz[ver];
        if(siz[ver]>maxsiz){
            maxsiz=siz[ver];
            pc[x]=ver;
        }
    }
}

void dfs2(int x,int topf){
    top[x]=topf;
    id[x]=++tot;
    num[tot]=x;
    if(!pc[x]) return;
    v[x].push_back(pc[x]);
    dfs2(pc[x],topf);
    for(int i=head[x];i;i=e[i].nxt){
        int ver=e[i].to;
        if(ver==fa[x]||ver==pc[x]) continue;
        v[x].push_back(ver);
        dfs2(ver,ver);
    }
}

inline int lca(int x,int y){
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]]) std::swap(x,y);
        x=fa[top[x]];
    }
    return dep[x]<dep[y]?x:y;
}

inline int FindSubtree(int x,int y){
    int l=0,r=v[x].size()-1;
    while(l<=r){
        int mid=((l+r)>>1);
        if(id[v[x][mid]]>id[y]) r=mid-1;
        else if(id[v[x][mid]]+siz[v[x][mid]]-1<id[y]) l=mid+1;
        else return v[x][mid];
    }
}

inline void AddTag(int x,int y,int z){
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]]) std::swap(x,y);
        v1[id[top[x]]].push_back(z);
        v2[id[x]+1].push_back(z);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y]) std::swap(x,y);
    v1[id[x]].push_back(z);
    v2[id[y]+1].push_back(z);
}

#define mid ((l+r)>>1)
#define lc (o<<1)
#define rc ((o<<1)|1)
void Build(int o,int l,int r){
    if(l==r){
        a[o].z=l;
        a[o].maxn=0;
        return;
    }
    Build(lc,l,mid);
    Build(rc,mid+1,r);
    a[o]=max(a[lc],a[rc]);
}

void Upd(int o,int l,int r){
    if(l==r&&l==loc){
        a[o].maxn+=k;
        return;
    }
    if(loc<=mid) Upd(lc,l,mid);
    else Upd(rc,mid+1,r);
    a[o]=max(a[lc],a[rc]);
}
#undef mid
#undef lc
#undef rc

int main(){
    n=read(),m=read();
    for(int i=1;i<n;i++){
        int u=read(),v=read();
        add_edge(u,v);
        add_edge(v,u);
    }
    dfs1(1,0,1);
    dfs2(1,1);
    for(int i=1;i<=m;i++){
        uu[i]=read();
        vv[i]=read();
        b[i]=zz[i]=read();
    }
    std::sort(b+1,b+m+1);
    int ValSiz=std::unique(b+1,b+m+1)-b-1;
    for(int i=1;i<=m;i++){
        int temp=zz[i];
        zz[i]=std::lower_bound(b+1,b+ValSiz+1,zz[i])-b;
        Flect[zz[i]]=temp;
        int _lca=lca(uu[i],vv[i]);
        if(_lca==vv[i]) AddTag(_lca,uu[i],zz[i]);
        else if(_lca==uu[i]) AddTag(_lca,vv[i],zz[i]);
        else{
            int temp=FindSubtree(_lca,vv[i]);
            AddTag(_lca,uu[i],zz[i]);
            AddTag(temp,vv[i],zz[i]);
        }
    }
    Build(1,1,ValSiz);
    for(int i=1;i<=n;i++){
        for(int j=0;j<v1[i].size();j++){
            loc=v1[i][j];k=1;
            Upd(1,1,ValSiz);
        }
        for(int j=0;j<v2[i].size();j++){
            loc=v2[i][j];k=-1;
            Upd(1,1,ValSiz);
        }
        ans[num[i]]=Flect[a[1].z];
        if(!a[1].maxn) ans[num[i]]=0;
    }
    for(int i=1;i<=n;i++)
        printf("%d\n",ans[i]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/ErkkiErkko/p/9668754.html