BZOJ3307 雨天的尾巴 (树链剖分 线段树合并 dfs相关)

来源:互联网 发布:武汉知黛化妆品靠谱吗 编辑:程序博客网 时间:2024/05/01 04:56

题目大意

N个点,形成一个树状结构。有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品。完成所有发放后,每个点存放最多的是哪种物品。


题解

看到这道题之后我本能的想法就是位置线段树套权值线段树的,但是看了一下,这道题的时间限制和空间限制卡得都比较紧,而且是离线问题,树套树卡起来应该是十分的困难的。

这道题虽然是处理树上问题,但是我们先考虑如何处理这样的区间问题。 如果所有的操作和询问都是在区间上进行的话,如在[x,y]区间内各放置一个z物品,就在x位置打上z物品+1的标记,在y+1位置打上z物品-1的标记。从左到右扫、处理标记,用一棵权值线段树维护。

从区间问题转化到了树上问题,通过这道题我学到了一种新的手段。

每次在一个树上路径上进行修改的时候,如修改x到y的路径的时候,只需要在x和y各打一个z物品+1的标记,在lca和fa[lca]打上z物品-1的标记,这样在dfs递归求解、向上合并的时候就可以做到不重不漏了。

因为在x和y打一个标记,这个标记的作用范围分别是x和y到根的路径(因为被这个标记修改后的线段树会一路被合并到根节点),但是从lca到根的路径上是被这个标记作用了两次的。所以给lca打上z物品-1的标记之后,lca到根的路径这个标记就只作用一次了;再给fa[lca]打上z物品-1的标记,这样这个标记就恰好只覆盖从x到y的路径了。

所以大概的思路就是:

  1. 处理出各个结点的标记
  2. 自下向上合并线段树
  3. 处理标记,修改线段树
  4. 把答案记录下来

代码

#include <cstdio>#include <iostream>#include <vector>#include <algorithm>using namespace std;const int maxn=int(1e5)+111, inf=int(1e9)+7;int n,m;int Tot=0,head[maxn];struct Edge {    int to,next;    Edge() {}    Edge(int y,int nx):to(y),next(nx) {}}eage[maxn*2];inline void add(int x,int y) {    eage[Tot]=Edge(y,head[x]), head[x]=Tot++;    eage[Tot]=Edge(x,head[y]), head[y]=Tot++;    return;}int fa[maxn],siz[maxn],dep[maxn],son[maxn];void dfs1(register int u) {    siz[u]=1, son[u]=0;    for(register int i=head[u];~i;i=eage[i].next) if(eage[i].to!=fa[u]) {        fa[eage[i].to]=u;        dep[eage[i].to]=dep[u]+1;        dfs1(eage[i].to);        siz[u]+=siz[eage[i].to];        if(siz[eage[i].to]>siz[son[u]]) son[u]=eage[i].to;    }    return;}int top[maxn],seq[maxn],id[maxn],ind;void dfs2(register int u) {    seq[id[u]=++ind]=u;    if(u==son[fa[u]]) top[u]=top[fa[u]];    else top[u]=u;    if(son[u]) dfs2(son[u]);    for(register int i=head[u];~i;i=eage[i].next) if(eage[i].to!=fa[u] && eage[i].to!=son[u])        dfs2(eage[i].to);    return;}inline int LCA(int u,int v) {    while(top[u]!=top[v]) {        if(dep[top[u]]<dep[top[v]]) std::swap(u,v);        u=fa[top[u]];    }    return dep[u]<dep[v]?u:v;}vector<pair<int,int> > op[maxn];#define pb push_back#define mp make_pairint v[maxn],vtop;struct Oper {    int x,y,z;}q[maxn];struct Node {    int ls,rs;    pair<int,int> pos;    inline Node() {        ls=rs=0;        pos=mp(0,0);    }}node[int(2e6)];int root[maxn],tot=0;int ans[maxn];inline void seg_merge(int k1,int k2,int l,int r) {    if(l==r) {        node[k1].pos.first+=node[k2].pos.first;        return;    }    register int &ls=node[k1].ls, &rs=node[k1].rs, mid=(l+r)>>1;    if(node[k2].ls) {        if(!ls) ls=node[k2].ls;        else seg_merge(ls,node[k2].ls,l,mid);    } if(node[k2].rs) {        if(!rs) rs=node[k2].rs;        else seg_merge(rs,node[k2].rs,mid+1,r);    }    if(ls) node[k1].pos=max(node[k1].pos,node[ls].pos);    if(rs) node[k1].pos=max(node[k1].pos,node[rs].pos);    return;}inline void seg_modify(int k,int l,int r,int pos,int val) {    if(l==r) {        node[k].pos.first+=val, node[k].pos.second=-pos;        return;    }    register int &ls=node[k].ls, &rs=node[k].rs, mid=(l+r)>>1;    if(pos<=mid) {        if(!ls) ls=++tot;        seg_modify(ls,l,mid,pos,val);        if(!node[ls].pos.first) ls=0;    } else {        if(!rs) rs=++tot;        seg_modify(rs,mid+1,r,pos,val);        if(!node[rs].pos.first) rs=0;    }    if(ls && rs) node[k].pos=max(node[ls].pos,node[rs].pos);    else if(ls) node[k].pos=node[ls].pos;    else if(rs) node[k].pos=node[rs].pos;    else node[k].pos=mp(0,0);    return;}inline void dfs(register int u) {    root[u]=++tot;    for(register int i=head[u];~i;i=eage[i].next) if(eage[i].to!=fa[u]) {        dfs(eage[i].to);        seg_merge(root[u],root[eage[i].to],1,vtop);    }    for(register int i=0;i<(int)op[u].size();i++) {        seg_modify(root[u],1,vtop,op[u][i].first,op[u][i].second);    }    ans[u]=-node[root[u]].pos.second;    return;}int main() {#ifndef ONLINE_JUDGE    freopen("input0.txt","r",stdin);    freopen("output.txt","w",stdout);#endif // ONLINE_JUDGE    scanf("%d%d",&n,&m);    for(int i=1;i<=n;i++)        head[i]=-1;    for(int x,y,i=1;i<n;i++) {        scanf("%d%d",&x,&y);        add(x,y);    }    dfs1(1),dfs2(1);    for(int i=1;i<=m;i++) {        scanf("%d%d%d",&q[i].x,&q[i].y,&q[i].z);        v[++vtop]=q[i].z;    }    sort(v+1,v+1+vtop);    vtop=unique(v+1,v+1+vtop)-(v+1);    for(int i=1;i<=m;i++) {        int x=q[i].x, y=q[i].y, z=lower_bound(v+1,v+1+vtop,q[i].z)-v;        op[x].pb(mp(z,+1)), op[y].pb(mp(z,+1));        int lca=LCA(x,y);        op[lca].pb(mp(z,-1)), op[fa[lca]].pb(mp(z,-1));    }    dfs(1);    for(int i=1;i<=n;i++) printf("%d\n",v[ans[i]]);    return 0;}
1 2