[bzoj 3531]sdoi2014 旅行

一眼树剖题

对每种颜色开一颗线段树,动态开点,记录最大值与和,查询直接查找,修改的话只会修改单点,所以最多增加2logn个节点

(原来把题目看错了,以为修改也是修改连续一段的,似乎这样空间会大很多)

#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
 
using namespace std;
const int Maxn = 1000005;
int sum[Maxn*10], maxx[Maxn*10];
int Fa[Maxn], fa[Maxn];
int dep[Maxn], T[Maxn];
int size[Maxn], dfn[Maxn];
int L[Maxn], R[Maxn];
int w[Maxn], c[Maxn];
int son[Maxn*10][2];
int n,Q,x,y,id,tim;
char S[10];
vector <int> e[Maxn];
 
void find_heavy_edge(int x){
  dep[x] = dep[fa[x]]+1;
  int len = e[x].size();
  size[x] = 1;
  for (int i=0;i<len;i++)
  if (e[x][i]!=fa[x]){
    fa[e[x][i]] = x;
    find_heavy_edge(e[x][i]);
    size[x] += size[e[x][i]];
  }
}
 
bool cmp(const int &a,const int &b)
{
  return size[a] > size[b];
}
 
void link_heavy_edge(int x){
  dfn[++tim] = x; L[x] = tim;
  sort(e[x].begin(),e[x].end(),cmp);
  if (x>1) e[x].erase( e[x].begin() );
    else Fa[x] = x;
  int len = e[x].size();
  for (int i=0;i<len;i++)
  {
    if (i==0) Fa[e[x][i]] = Fa[x];
      else Fa[e[x][i]] = e[x][i];
    link_heavy_edge(e[x][i]);
  }
  R[x] = tim;
}
 
void insert(int &p,int l,int r,int pos,int data){
  if (p==0) p = ++id;
  if (l==r){
    sum[p] = maxx[p] = data;
    return;
  }
  int mid = (l+r)>>1;
  if (mid>=pos) insert(son[p][0],l,mid,pos,data);
    else insert(son[p][1],mid+1,r,pos,data);
  sum[p] = sum[son[p][0]] + sum[son[p][1]];
  maxx[p] = max( maxx[son[p][0]], maxx[son[p][1]] );
}
 
int query_sum(int p,int l,int r,int L,int R){
  if (p==0) return 0;
  if (L>r || l>R) return 0;
  if (L<=l && R>=r) return sum[p];
  int mid = (l+r)>>1;
  return query_sum(son[p][0],l,mid,L,R) + query_sum(son[p][1],mid+1,r,L,R);
}
 
int query_max(int p,int l,int r,int L,int R){
  if (p==0) return 0;
  if (L>r || l>R) return 0;
  if (L<=l && R>=r) return maxx[p];
  int mid = (l+r)>>1;
  return max( query_max(son[p][0],l,mid,L,R), query_max(son[p][1],mid+1,r,L,R) );
}
 
void work1(){
  insert(T[c[x]],1,n,L[x],0);
  c[x] = y;
  insert(T[c[x]],1,n,L[x],w[x]);
}
 
void work2(){
  w[x] = y;
  insert(T[c[x]],1,n,L[x],w[x]);
}
 
void work3(){
  int col = c[x], ans = 0;
  while (Fa[x]!=Fa[y])
  {
    if (dep[Fa[x]]<dep[Fa[y]]) swap(x,y);
    ans += query_sum(T[col],1,n,L[Fa[x]],L[x]);
    x = fa[Fa[x]];
  }
  if (L[x]>L[y]) swap(x,y);
  ans += query_sum(T[col],1,n,L[x],L[y]);
  printf("%d\n",ans);
}
 
void work4(){
  int col = c[x], ans = 0;
  while (Fa[x]!=Fa[y])
  {
    if (dep[Fa[x]]<dep[Fa[y]]) swap(x,y);
    ans = max(ans, query_max(T[col],1,n,L[Fa[x]],L[x]) );
    x = fa[Fa[x]];
  }
  if (L[x]>L[y]) swap(x,y);
  ans = max(ans, query_max(T[col],1,n,L[x],L[y]) );
  printf("%d\n",ans);
}
 
int main(){
  scanf("%d%d",&n,&Q);
  for (int i=1;i<=n;i++)
    scanf("%d%d",&w[i],&c[i]);
  for (int i=1;i<n;i++){
    scanf("%d%d",&x,&y);
    e[x].push_back(y);
    e[y].push_back(x);
  }
  find_heavy_edge(1);
  link_heavy_edge(1);
  for (int i=1;i<=n;i++)
    insert(T[c[i]],1,n,L[i],w[i]);
  while (Q--){
    scanf("%s%d%d",S,&x,&y);
    if (S[0]=='C' && S[1]=='C') work1();
    if (S[0]=='C' && S[1]=='W') work2();
    if (S[0]=='Q' && S[1]=='S') work3();
    if (S[0]=='Q' && S[1]=='M') work4();
  }
  return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值