P3950 部落衝突

2022-04-30 19:15:11 字數 3433 閱讀 6966

此題用樹鏈剖分是大材小用了,因為它可以處理 \(p,q\) 不相鄰的情況。

簡化一下題意:

這都是一些樹上的操作,乍一看可以用樹剖直接搞。但是因為這裡是進行操作,所以我們可以以點代邊,把邊看做點。每一次查詢的時候 \(lca(p,q)\) 是不能算的。

如果 \(p,q\) 不相鄰,我們可以加入樹剖的修改操作,但是線段樹的修改操作就必須是區間賦值,需要打乙個精妙的標記。

時間複雜度: \(o(n\log^2 n)\),常數巨大。

// luogu-judger-enable-o2

uses math;

var recf,cnt,size,dfn,dep,top,father,son:array[-1..3100000] of longint;

next,reach:array[-1..8500000] of longint;

left,right:array[-1..8500000] of longint;

ques:array[-1..3100000] of longint;

tree:array[-1..15000000] of int64; // 線段樹的空間要開大

i,n,m,l,r,dfnum,tot,root,tail:longint;

order:char;

procedure swap(var a,b:longint);var t:longint; begin t:=a; a:=b; b:=t; end;

procedure add(l,r:longint);

begin

inc(tot);

reach[tot]:=r;

next[tot]:=cnt[l];

cnt[l]:=tot;

end;

procedure dfs_1(x:longint);

var i:longint;

begin

size[x]:=1; i:=cnt[x]; size[0]:=-maxlongint div 843;

while i<>-1 do

begin

if dep[reach[i]]=0 then

begin

dep[reach[i]]:=dep[x]+1;

father[reach[i]]:=x;

dfs_1(reach[i]); inc(size[x],size[reach[i]]);

if size[reach[i]]>size[son[x]] then son[x]:=reach[i];

end;

i:=next[i];

end;

end;

procedure dfs_2(x,centre:longint);

var i:longint;

begin

inc(dfnum); dfn[x]:=dfnum; recf[dfnum]:=x; top[x]:=centre;

if son[x]=0 then exit; dfs_2(son[x],centre);

i:=cnt[x];

while i<>-1 do

begin

if (reach[i]<>father[x])and(reach[i]<>son[x]) then dfs_2(reach[i],reach[i]);

i:=next[i];

end;

end;

procedure build(k,l,r:longint);

var mid:longint;

begin

left[k]:=l; right[k]:=r;

if (l=r) then exit;

mid:=(l+r) >> 1;

build(k << 1,l,mid); build(k << 1+1,mid+1,r);

end;

procedure change(k,x,modify:longint);

var mid:longint;

begin

if left[k]=right[k] then begin inc(tree[k],modify); exit; end;

mid:=(left[k]+right[k]) >> 1;

if x<=mid then change(k << 1,x,modify) else change(k << 1+1,x,modify);

tree[k]:=tree[k << 1]+tree[k << 1+1];

end;

function query(k,x,y:longint):int64;

var mid:longint;

begin

query:=0;

if x>y then exit(0);

if (x<=left[k])and(right[k]<=y) then exit(tree[k]);

mid:=(left[k]+right[k]) >> 1;

if mid>=y then inc(query,query(k << 1,x,y)) else

if midtop[y] do

begin

if dep[top[x]]=1 then exit('no'); // 如果這一段有乙個黑色,那麼 no

x:=father[top[x]];

end;

if dep[x]>dep[y] then swap(x,y);

tmp:=query(1,dfn[x]+1,dfn[y]); if tmp>=1 then exit('no'); // dfn[x]+1 是因為 lca(x,y) 不能加

exit('yes');

end;

begin

filldword(cnt,sizeof(cnt) div 4,maxlongint*2+1);

readln(n,m); root:=1; recf[-1]:=-1;

for i:=1 to n-1 do begin readln(l,r); add(l,r); add(r,l); end;

dep[root]:=1; father[root]:=1;

dfs_1(root); dfs_2(root,root); build(1,1,n);

for i:=1 to m do

begin

read(order);

if order='c' then begin readln(l,r); if dep[l]if order='q' then begin readln(l,r); writeln(refer(l,r));end;

if order='u' then begin readln(l); change(1,dfn[ques[l]],-1); end;

end;

end.

洛谷P3950 部落衝突 LCT

題目傳送門 格式難調,體面就不放了。分析 julao們應該都看得出來就是個 lct 板子,戰爭就 cut 結束就 link 詢問就 find 沒了。太久沒打 lct 然後發現自己之前貌似理解得並不透徹,打得還是不熟。code it is made by holselee on 5th sep 201...

題解 洛谷P3950 部落衝突

text quad 一道很簡單的樹剖題,只有三種操作 其實是兩種 唯一要考慮的點是如何將邊權轉化成點權,考慮到每個點都有且只有乙個父親節點 除根節點1之外 那麼我們就可以將父親與兒子連線的邊權記錄到兒子身上,這樣 n 1 條邊就可以合理的分配到 n 1 個點上 除了根節點 這樣就轉化成了普通的樹鏈剖...

P3950 部落衝突(樹鏈剖分)

簡單起見,你就是要處理下面三件事,所有的事件都是按照時間順序給出的。q p q從第 pp 個部落出發的建築工人想知道能否到達第 qq 個部落了,你要回答的便是yes no,注意大小寫。c p q第 pp 個部落與第 qq 個部落開戰了,保證他們一定是相鄰的部落,且目前處於停戰 未開戰 狀態。u x第...