[BZOJ3531] SDOI2014 树链剖分+动态开点线段树

首先发现是一棵树,想到树链剖分来维护路径。
但是如何把不同宗教的点分开计数?想到给每一个宗教开一颗线段树来维护,因为总共点数只有10^5个,可以采取动态开点来保证内存不超。
代码

type
  xtree=^xtreenode;
  xtreenode=record
    max,sum,l,r:longint;
    ls,rs:xtree;
  end;
  edge=^edgenode;
  edgenode=record
    t:longint;
    next:edge;
  end;
var
  n,q,i,j,u,v,time,ans,ck,x,y:longint;
  c1:char;
  w,c,dfn,fdfn,deep,size,head,hs,fa:array[0..100100]of longint;
  con:array[1..100100]of edge;
  xtr:array[1..100100]of xtree;
procedure ins(x,y:longint);
var
  p:edge;
begin
  new(p);
  p^.t:=y;
  p^.next:=con[x];
  con[x]:=p;
end;
function maxx(x,y:longint):longint;
begin
  if x>y then exit(x)
  else exit(y);
end;
procedure outp(x:xtree);
begin
  if x=nil then exit;
  writeln(x^.l,' ',x^.r,' ',x^.max,' ',x^.sum);
  outp(x^.ls);
  outp(x^.rs);
end;

procedure dfs1(v:longint);
var
  p:edge;
  max,maxi:longint;
begin
  size[v]:=1;
  deep[v]:=deep[fa[v]]+1;
  p:=con[v];
  max:=0;
  maxi:=0;
  while p<>nil do
  begin
    if p^.t<>fa[v] then
    begin
      fa[p^.t]:=v;
      dfs1(p^.t);
      if size[p^.t]>max then begin max:=size[p^.t]; maxi:=p^.t end;
      size[v]:=size[v]+size[p^.t];
    end;
    p:=p^.next;
  end;
  hs[v]:=maxi;
end;
procedure dfs2(v:longint);
var
  p:edge;
begin
  inc(time);
  dfn[v]:=time;
  fdfn[time]:=v;
  if hs[fa[v]]=v then head[v]:=head[fa[v]]
  else head[v]:=v;
  p:=con[v];
  if hs[v]>0 then dfs2(hs[v]);
  while p<>nil do
  begin
    if (p^.t<>fa[v])and(p^.t<>hs[v]) then dfs2(p^.t);
    p:=p^.next;
  end;
end;
procedure build(var x:xtree;sum,max,l,r:longint);
begin
  new(x);
  x^.l:=l;
  x^.r:=r;
  x^.max:=max;
  x^.sum:=sum;
  x^.ls:=nil;
  x^.rs:=nil;
end;

procedure updata(var x:xtree);
begin
  x^.sum:=0;
  x^.max:=0;
  if x^.ls<>nil then begin x^.sum:=x^.ls^.sum; x^.max:=x^.ls^.max; end;
  if x^.rs<>nil then begin x^.sum:=x^.sum+x^.rs^.sum; x^.max:=maxx(x^.max,x^.rs^.max) ; end;
end;

procedure change(var x:xtree;v,nw,l,r:longint);
var
  mid:longint;
begin
  if x=nil then build(x,0,0,l,r);
  if l=r then begin x^.max:=nw; x^.sum:=nw; exit; end;
  mid:=(l+r) div 2;
  if (v>=l)and(v<=mid) then change(x^.ls,v,nw,l,mid)
  else change(x^.rs,v,nw,mid+1,r);
  updata(x);
end;

procedure dele(var x:xtree;v,nw,l,r:longint);
var
  mid:longint;
begin
  if l=r then begin  x:=nil; exit; end;
  mid:=(l+r) div 2;
  if (v>=l)and(v<=mid) then  dele(x^.ls,v,nw,l,mid)
  else dele(x^.rs,v,nw,mid+1,r);
  updata(x);
  if x^.sum=0 then begin  x:=nil; exit; end;
end;
function qsum(x:xtree;l,r:longint):longint;
var
  mid:longint;
begin
  if x=nil then exit(0);
  if (l=x^.l)and(r=x^.r) then exit(x^.sum);
  mid:=(x^.l+x^.r)div 2;
  if r<=mid then exit(qsum(x^.ls,l,r));
  if l>mid  then exit(qsum(x^.rs,l,r));
  exit(qsum(x^.ls,l,mid)+qsum(x^.rs,mid+1,r));

end;

function qmax(x:xtree;l,r:longint):longint;
var
  mid:longint;
begin
  if x=nil then exit(0);
  if (l=x^.l)and(r=x^.r) then exit(x^.max);
  mid:=(x^.l+x^.r)div 2;
  if r<=mid then exit(qmax(x^.ls,l,r));
  if l>mid  then exit(qmax(x^.rs,l,r));
  exit(maxx(qmax(x^.ls,l,mid),qmax(x^.rs,mid+1,r)));
end;
begin
  readln(n,q);
  for i:=1 to n do
    readln(w[i],c[i]);
  for i:=1 to n-1 do
  begin
    readln(u,v);
    ins(u,v);
    ins(v,u);
  end;
  dfs1(1);
  dfs2(1);
  for i:=1 to n do
    change(xtr[c[i]],dfn[i],w[i],1,n);
  for i:=1 to q do
  begin
    {for j:=1 to 3 do
    begin
      outp(xtr[j]);
      writeln;
    end; }
    ans:=0;
    read(c1);read(c1); readln(x,y);
    ck:=c[x];
    case c1 of
      'C':begin dele(xtr[c[x]],dfn[x],w[x],1,n); c[x]:=y; change(xtr[y],dfn[x],w[x],1,n) end;
      'W':begin w[x]:=y; change(xtr[c[x]],dfn[x],y,1,n) end;
      'S':
      begin
        while head[x]<>head[y] do
        begin
          if deep[head[x]]>deep[head[y]] then
          begin
            ans:=ans+qsum(xtr[ck],dfn[head[x]],dfn[x]);
            x:=fa[head[x]];
          end
          else
          begin
            ans:=ans+qsum(xtr[ck],dfn[head[y]],dfn[y]);
            y:=fa[head[y]];
          end;
        end;
        if deep[x]<=deep[y] then ans:=ans+qsum(xtr[ck],dfn[x],dfn[y])
        else ans:=ans+qsum(xtr[ck],dfn[y],dfn[x]);
        writeln(ans);
      end;
      'M':
      begin
        while head[x]<>head[y] do
        begin
          if deep[head[x]]>deep[head[y]] then
          begin
            ans:=maxx(ans,qmax(xtr[ck],dfn[head[x]],dfn[x]));
            x:=fa[head[x]];
          end
          else
          begin
            ans:=maxx(ans,qmax(xtr[ck],dfn[head[y]],dfn[y]));
            y:=fa[head[y]];
          end;
        end;
        if deep[x]<=deep[y] then ans:=maxx(ans,qmax(xtr[ck],dfn[x],dfn[y]))
        else ans:=maxx(ans,qmax(xtr[ck],dfn[y],dfn[x]));
        writeln(ans);
      end;
    end;
  end;
end. 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值