[BZOJ] 3307: 雨天的尾巴

题意:给一颗树,每次在一条路径上增加一种物品,问每个点为根的子树中最多的物品的种类

每个点维护一颗权值线段树,树上差分,复杂度O((n+m)logn)

实际操作中,权值线段树叶子节点维护出现次数,非叶子节点维护子树max值和出现位置,其实也可以只维护max值,统计答案时二分统计

第一个版本是直接开了1~1e9的权值线段树,常数较大

#include<iostream>
#include<cstdio>

using namespace std;

const int MAXN=100005*60;

inline int rd(){
  int ret=0,f=1;char c;
  while(c=getchar(),!isdigit(c))f=c=='-'?-1:1;
  while(isdigit(c))ret=ret*10+c-'0',c=getchar();
  return ret*f;
}

struct Edge{
  int next,to;
}e[MAXN<<1];
int ecnt,head[MAXN];
inline void add(int x,int y){
  e[++ecnt].next = head[x];
  e[ecnt].to = y;
  head[x] = ecnt;
}

int dep[MAXN],fa[MAXN],hson[MAXN],siz[MAXN];
void dfs1(int x,int pre){
  dep[x]=dep[pre]+1;fa[x]=pre;siz[x]=1;
  int sz=0;
  for(int i=head[x];i;i=e[i].next){
    int v=e[i].to;
    if(v==pre)continue;
    dfs1(v,x);siz[x]+=siz[v];
    if(siz[v]>sz){sz=siz[v];hson[x]=v;}
  }
}
int top[MAXN];
void dfs2(int x,int tp){
  top[x]=tp;
  if(hson[x])dfs2(hson[x],tp);
  for(int i=head[x];i;i=e[i].next){
      int v=e[i].to;
      if(v==fa[x]||v==hson[x])continue;
      dfs2(v,v);
  }
}
int lca(int x,int y){
  while(top[x]!=top[y]){
    dep[top[x]]>=dep[top[y]]?x=fa[top[x]]:y=fa[top[y]];
  }
  return dep[x]<=dep[y]?x:y;
}

int rt[MAXN],num;
int val[MAXN],mx[MAXN],mxp[MAXN],ch[MAXN][2];
inline int newnode(){return ++num;}
inline void pushup(int cur){
  int x=ch[cur][0],y=ch[cur][1];
  int u=mx[x]<mx[y];
  mxp[cur]=mxp[ch[cur][u]];
  mx[cur]=mx[ch[cur][u]];
}
void update(int x,int &cur,int l,int r,int w){
  if(!cur)cur=newnode();
  if(l==r){mx[cur]+=w;mxp[cur]=l;return;}
  int mid=(l+r)>>1;
  if(x<=mid)update(x,ch[cur][0],l,mid,w);
  else update(x,ch[cur][1],mid+1,r,w);
  pushup(cur);
}
void merge(int &u,int v,int l,int r){
  if(!u||!v) {u=u+v;return;}
  if(l==r){
    mx[u]+=mx[v];
    mxp[u]=l;
    return;
  }
  int mid=(l+r)>>1;
  merge(ch[u][0],ch[v][0],l,mid);
  merge(ch[u][1],ch[v][1],mid+1,r);
  pushup(u);
}
int n,m;
struct Node{
  int x,y,w;
}a[MAXN];
int tmp[MAXN],ans[MAXN];
void dfs(int x){
  for(int i=head[x];i;i=e[i].next){
    int v=e[i].to;
    if(v==fa[x])continue;
    dfs(v);
    merge(rt[x],rt[v],1,1e9);
  }
  ans[x]=mxp[rt[x]];
}
int main(){
  n=rd();m=rd();
  int x,y,w;
  for(int i=1;i<n;i++){
    x=rd();y=rd();
    add(x,y);add(y,x);
  }
  dfs1(1,0);dfs2(1,1);
  for(register int i=1;i<=m;i++){
    x=rd();y=rd();tmp[i]=w=rd();
    update(w,rt[x],1,1e9,1);
    update(w,rt[y],1,1e9,1);
    int l=lca(x,y);
    update(w,rt[l],1,1e9,-1);
    if(l=fa[l])update(w,rt[l],1,1e9,-1);
  }
  dfs(1);
  for(register int i=1;i<=n;i++){
    printf("%d\n",ans[i]);
  }
}
View Code

第二个版本先离散化,开一棵1~m的权值线段树,快了一倍qwq

#include<algorithm>
#include<iostream>
#include<cstdio>

using namespace std;

const int MAXN=100005;
const int N=MAXN*60;
inline int rd(){
  int ret=0,f=1;char c;
  while(c=getchar(),!isdigit(c))f=c=='-'?-1:1;
  while(isdigit(c))ret=ret*10+c-'0',c=getchar();
  return ret*f;
}

struct Edge{
  int next,to;
}e[MAXN<<1];
int ecnt,head[MAXN];
inline void add(int x,int y){
  e[++ecnt].next = head[x];
  e[ecnt].to = y;
  head[x] = ecnt;
}

int dep[MAXN],fa[MAXN],hson[MAXN],siz[MAXN];
void dfs1(int x,int pre){
  dep[x]=dep[pre]+1;fa[x]=pre;siz[x]=1;
  int sz=0;
  for(int i=head[x];i;i=e[i].next){
    int v=e[i].to;
    if(v==pre)continue;
    dfs1(v,x);siz[x]+=siz[v];
    if(siz[v]>sz){sz=siz[v];hson[x]=v;}
  }
}
int top[MAXN];
void dfs2(int x,int tp){
  top[x]=tp;
  if(hson[x])dfs2(hson[x],tp);
  for(int i=head[x];i;i=e[i].next){
      int v=e[i].to;
      if(v==fa[x]||v==hson[x])continue;
      dfs2(v,v);
  }
}
int lca(int x,int y){
  while(top[x]!=top[y]){
    dep[top[x]]>=dep[top[y]]?x=fa[top[x]]:y=fa[top[y]];
  }
  return dep[x]<=dep[y]?x:y;
}

int rt[MAXN],num;
int val[N],mx[N],mxp[N],ch[N][2];
inline int newnode(){return ++num;}
inline void pushup(int cur){
  int u=mx[ch[cur][0]]<mx[ch[cur][1]];
  mxp[cur]=mxp[ch[cur][u]];
  mx[cur]=mx[ch[cur][u]];
}
void update(int x,int &cur,int l,int r,int w){
  if(!cur)cur=newnode();
  if(l==r){mx[cur]+=w;mxp[cur]=l;return;}
  int mid=(l+r)>>1;
  if(x<=mid)update(x,ch[cur][0],l,mid,w);
  else update(x,ch[cur][1],mid+1,r,w);
  pushup(cur);
}
void merge(int &u,int v,int l,int r){
  if(!u||!v) {u=u+v;return;}
  if(l==r){
    mx[u]+=mx[v];
    mxp[u]=l;
    return;
  }
  int mid=(l+r)>>1;
  merge(ch[u][0],ch[v][0],l,mid);
  merge(ch[u][1],ch[v][1],mid+1,r);
  pushup(u);
}
int n,m,tot;
int ans[MAXN];
void dfs(int x){
  for(int i=head[x];i;i=e[i].next){
    int v=e[i].to;
    if(v==fa[x])continue;
    dfs(v);
    merge(rt[x],rt[v],1,tot);
  }
  ans[x]=mxp[rt[x]];
}

struct Node{
    int x,y,w;
}a[MAXN];
int tmp[MAXN];
int main(){
  n=rd();m=rd();
  int x,y,w;
  for(int i=1;i<n;i++){
    x=rd();y=rd();
    add(x,y);add(y,x);
  }
  dfs1(1,0);dfs2(1,1);
  for(register int i=1;i<=m;i++){
    a[i].x=rd();a[i].y=rd();a[i].w=tmp[i]=rd();
  }
  sort(tmp+1,tmp+1+m);
  tot=unique(tmp+1,tmp+1+m)-tmp-1;
  for(int i=1;i<=m;i++){
      int x=a[i].x,y=a[i].y,w=lower_bound(tmp+1,tmp+1+tot,a[i].w)-tmp; 
    update(w,rt[x],1,tot,1);
    update(w,rt[y],1,tot,1);
    int l=lca(x,y);
    update(w,rt[l],1,tot,-1);
    if(l=fa[l])update(w,rt[l],1,tot,-1);
  }
  dfs(1);
  for(register int i=1;i<=n;i++){
    printf("%d\n",tmp[ans[i]]);
  }
}
View Code

 

posted @ 2018-09-13 17:08  GhostCai  阅读(156)  评论(0编辑  收藏  举报