NOIP11 15模擬 T2 三部曲

2021-07-24 15:15:52 字數 4227 閱讀 6898

。。沒想到正解,大概知道是線段樹,但是不知道怎麼處理,出來才知道是用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肯定是單調遞增...