。。沒想到正解,大概知道是線段樹,但是不知道怎麼處理,出來才知道是用dfs序,也有dalao用樹剖怒艹。。然而我明明打的50分結果只有30分,a了之後看了一下別人50分的做法。。感覺我就算是暴力都打的很複雜。。有很多可以簡化的東西。。要學習一下。
簡潔的50分做法(來自hhh)
當然還有我的滿分做法:#include
#include
#include
#include
#include
#define ll long long
using
namespace
std;
const
char* fin="truetears.in";
const
char* fout="truetears.out";
const
int inf=0x7fffffff;
const
int maxn=50007,maxm=maxn*2;
int n,m,i,j,k;
int fi[maxn],ne[maxm],la[maxm],tot;
ll a[maxn],ans;
int fa[maxn];
char ch;
void add_line(int a,int b)
void add(int v,int from,int ad)
}void getans(int v,int from)
int main()
scanf("\n");
for (i=1;i<=m;i++)else
var
i,j,k,p,n,m,tot,id,x,y:longint;
dfn,size,dep,fa,tmp:array[0..50010]of longint;
head,go,next:array[0..200000]of longint;
sum:array[0..200000]of int64;
ds,siz:array[0..200000]of longint;
tag:array[0..200000,0..2]of longint;
ch:char;
procedure
add(x,y:longint);
begin
inc(tot);
go[tot]:=y;
next[tot]:=head[x];
head[x]:=tot;
end;
procedure
dfs(x:longint);
var i,v:longint;
begin
inc(id);
dfn[x]:=id;
tmp[id]:=dep[x];
size[x]:=1;
i:=head[x];
while i<>0
dobegin
v:=go[i];
dep[v]:=dep[x]+1;
dfs(v);
size[x]:=size[x]+size[v];
i:=next[i];
end;
end;
procedure
build
(x,l,r:longint);
var mid:longint;
begin
if (l=r) then
begin
siz[x]:=1;
ds[x]:=tmp[l];
exit;
end;
mid:=(l+r)div
2; build(x*2,l,mid);
build(x*2+1,mid+1,r);
siz[x]:=siz[x*2]+siz[x*2+1];
ds[x]:=ds[x*2]+ds[x*2+1];
end;
procedure
addd
(x,x1,x2:longint);
begin
sum[x]:=sum[x]+x1*siz[x]+x2*ds[x];
tag[x,0]:=tag[x,0]+x1;
tag[x,1]:=tag[x,1]+x2;
end;
procedure
update
(x:longint);
begin
sum[x]:=sum[x*2]+sum[x*2+1];
end;
procedure
clear
(x,l,r:longint);
var mid:longint;
begin
if (l<>r)and((tag[x,0]<>0)or(tag[x,1]<>0))then
begin
addd(x*2,tag[x,0],tag[x,1]);
addd(x*2+1,tag[x,0],tag[x,1]);
tag[x,0]:=0;
tag[x,1]:=0;
end;
end;
procedure
modify
(x,l1,r1,l,r,z:longint);
var mid:longint;
begin
clear(x,l,r);
if (l1=l)and(r1=r) then
begin
addd(x,z,1);
clear(x,l,r);
exit;
end;
mid:=(l+r)div
2; if r1<=mid then modify(x*2,l1,r1,l,mid,z)
else
if mid+1
<=l1 then modify(x*2+1,l1,r1,mid+1,r,z)
else
begin
modify(x*2,l1,mid,l,mid,z);
modify(x*2+1,mid+1,r1,mid+1,r,z);
end;
update(x);
end;
function
query
(x,l1,r1,l,r:longint):int64;
var mid:longint;
begin
clear(x,l,r);
if (r1=r)and(l1=l) then
exit(sum[x]);
mid:=(l+r)div
2; if r1<=mid then
exit(query(x*2,l1,r1,l,mid))
else
if mid+1
<=l1 then
exit(query(x*2+1,l1,r1,mid+1,r))
else
begin
exit(query(x*2,l1,mid,l,mid)+query(x*2+1,mid+1,r1,mid+1,r));
end;
end;
begin
assign(input,'truetears.in');
assign(output,'truetears.out');
reset(input);
rewrite(output);
readln(n,m);
for i:=2
to n do
begin
read(fa[i]);
add(fa[i],i);
end;
readln;
dep[1]:=1;
fa[1]:=0;
dfs(1);
build(1,1,n);
for i:=1
to m do
begin
read(ch);
if ch='q'
then
begin
readln(x);
writeln(query(1,dfn[x],dfn[x]+size[x]-1,1,id));
endelse
begin
readln(x,y);
modify(1,dfn[x],dfn[x]+size[x]-1,1,id,y-dep[x]);
end;
end;
end.
NOIP 模擬題 T2 寶藏(樹形dp)
題解 樹形dp 其實這道題說起來很簡單,用四個陣列 d1 d0 u0 u1分別表示從當前點向下更新,不返回 從當前點向下更新再回到當前點 從當前點向上更新回到當前點 從當前點向上更新不返回。用兩遍dfs求出這四個陣列 實現起來細節會比較多,耐心處理 include include include d...
NOIP校內模擬 T2 字胡串(分治)
lst神仙 這是他的做法 吊了標算 對於這種有多少區間滿足要求的 我們套路的用分治做 每次都統計左端點在左半邊 右端點在右半邊的個數 設f i 表示當前點到中間分割點的最大值,g i 表示當前點到中間分割點的或和 我們發現 g i f i 所以只需找到g i f i 的區間就好 然後f肯定是單調遞增...
NOIP校內模擬 T2 字胡串(分治)
lst神仙 這是他的做法 吊了標算 對於這種有多少區間滿足要求的 我們套路的用分治做 每次都統計左端點在左半邊 右端點在右半邊的個數 設f i 表示當前點到中間分割點的最大值,g i 表示當前點到中間分割點的或和 我們發現 g i f i 所以只需找到g i f i 的區間就好 然後f肯定是單調遞增...