Codeforces 343D Water Tree

传送门

http://codeforces.com/problemset/problem/343/D

题目大意

给定一棵树,要求支持如下操作
1.对于a的子树全部赋值为1
2.对于a到根的路径上的点都赋值为0
3.单点查询

题解

路径修改+子树修改+单点查询依照我数据结构总结里的子树修改+单点查询和路径修改+单点查询即可完成
但是,还存在有两个问题
1.子树修改转区间修改时的标记下放
2.子树中某点打完贡献标记后,要对子树中的某个子树执行操作1,他的贡献标记怎么处理
我们维护3个域
1.点权值
2.贡献标记
3.区间变1标记
操作1:查询a的子树中有没有贡献标记,如果有且a有父节点,那么对a的父节点打上贡献标记,然后区间修改,点的权值为0,贡献标记取消
操作2:单点修改a的贡献标记
操作3:先查询a子树的贡献标记,如果有,输出0,如果没有输出a的单点权值
以上需要支持:修改区间为0+修改单点贡献标记+查询子树的贡献标记+查询单点权值

const
 maxn=500005;
var
 w:array[0..4*maxn,1..5]of longint;
 x:array[0..4*maxn,1..2]of longint;
 y:array[0..maxn,1..2]of longint;
 fa:array[0..maxn]of longint;
 i,j,k:longint;
 n,m,a,b,len,tt:longint;
procedure init(a,b:longint);
begin
 x[len,1]:=b;
 if x[a,2]=0
 then x[a,2]:=len else x[x[a,1],2]:=len;
 x[a,1]:=len; inc(len);
end;

procedure dfs(a:longint);
var tt:longint;
begin
 inc(len); y[a,1]:=len; tt:=x[a,2];
 while tt<>0 do
  begin
   if y[x[tt,1],1]=0 then begin fa[x[tt,1]]:=a; dfs(x[tt,1]); end;
   tt:=x[tt,2];
  end;
 y[a,2]:=len;
end;

procedure build(a,l,r:longint);
var mid:longint;
begin
 w[a,1]:=l; w[a,2]:=r; w[a,3]:=0; w[a,4]:=0; w[a,5]:=-1;
 if l=r then exit;
 mid:=(l+r)>>1;
 build(a<<1,l,mid); build(a<<1+1,mid+1,r);
end;

procedure pushdown(a:longint);
begin
 if w[a,1]=w[a,2] then begin w[a,5]:=-1; exit; end;
 w[a<<1,3]:=1; w[a<<1,4]:=0; w[a<<1,5]:=1; w[a<<1+1,3]:=1; w[a<<1+1,4]:=0; w[a<<1+1,5]:=1;
 w[a,5]:=-1;
end;

function query1(a,l,r:longint):longint;
var mid:longint;
begin
 if w[a,5]<>-1 then pushdown(a);
 if (l=w[a,1])and(r=w[a,2]) then exit(w[a,4]);
 mid:=(w[a,1]+w[a,2])>>1;
 if r<=mid then exit(query1(a<<1,l,r)) else
 if l>mid then exit(query1(a<<1+1,l,r))
 else exit(query1(a<<1,l,mid)or query1(a<<1+1,mid+1,r));
end;

function query2(a,b:longint):longint;
var mid:longint;
begin
 if w[a,5]<>-1 then pushdown(a);
 if (w[a,1]=w[a,2])and(w[a,1]=b) then exit(w[a,3]);
 mid:=(w[a,1]+w[a,2])>>1;
 if b<=mid then exit(query2(a<<1,b)) else exit(query2(a<<1+1,b));
end;

procedure update1(a,b:longint);
var mid:longint;
begin
 if w[a,5]<>-1 then pushdown(a);
 if (w[a,1]=w[a,2])and(w[a,1]=b) then begin w[a,4]:=1; exit; end;
 mid:=(w[a,1]+w[a,2])>>1;
 if b<=mid then update1(a<<1,b) else update1(a<<1+1,b);
 w[a,4]:=w[a<<1,4] or w[a<<1+1,4];
end;

procedure update2(a,l,r:longint);
var mid:longint;
begin
 if w[a,5]<>-1 then pushdown(a);
 if (w[a,1]=l)and(w[a,2]=r) then begin w[a,3]:=1; w[a,4]:=0; w[a,5]:=1; exit; end;
 mid:=(w[a,1]+w[a,2])>>1;
 if r<=mid then update2(a<<1,l,r) else
 if l>mid then update2(a<<1+1,l,r)
 else begin update2(a<<1,l,mid); update2(a<<1+1,mid+1,r); end;
 w[a,4]:=w[a<<1,4] or w[a<<1+1,4];
end;

begin
 readln(n); len:=n+1;
 for i:=1 to n-1 do
  begin
   readln(a,b); init(a,b); init(b,a);
  end;
 len:=0; dfs(1);
 build(1,1,n);
 readln(m);
 for i:=1 to m do
  begin
   readln(a,b);
   case a of
   1:begin
    tt:=query1(1,y[b,1],y[b,2]);
    if (tt=1)and(fa[b]<>0) then update1(1,y[fa[b],1]);
    update2(1,y[b,1],y[b,2]); {writeln(tt);}
   end;
   2:begin update1(1,y[b,1]); end;
   3:begin
    tt:=query1(1,y[b,1],y[b,2]);
    if tt=1 then writeln(0) else writeln(query2(1,y[b,1]));
   end;
   end;
  end;
end.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值