P1505 國家集訓隊 旅遊 樹鏈剖分

2021-08-18 08:26:05 字數 3960 閱讀 3609

題目描述

ray 樂忠於旅遊,這次他來到了t 城。t 城是乙個水上城市,一共有 n 個景點,有些景點之間會用一座橋連線。為了方便遊客到達每個景點但又為了節約成本,t 城的任意兩個景點之間有且只有一條路徑。換句話說, t 城中只有n − 1 座橋。

ray 發現,有些橋上可以看到美麗的景色,讓人心情愉悅,但有些橋狹窄泥濘,令人煩躁。於是,他給每座橋定義乙個愉悅度w,也就是說,ray 經過這座橋會增加w 的愉悅度,這或許是正的也可能是負的。有時,ray 看待同一座橋的心情也會發生改變。

現在,ray 想讓你幫他計算從u 景點到v 景點能獲得的總愉悅度。有時,他還想知道某段路上最美麗的橋所提供的最大愉悅度,或是某段路上最糟糕的一座橋提供的最低愉悅度。

輸入格式:

輸入的第一行包含乙個整數n,表示t 城中的景點個數。景點編號為 0…n − 1。

接下來n − 1 行,每行三個整數u、v 和w,表示有一條u 到v,使 ray 愉悅度增加w 的橋。橋的編號為1…n − 1。|w| <= 1000。 輸入的第n + 1 行包含乙個整數m,表示ray 的運算元目。

接下來有m 行,每行描述了乙個操作,操作有如下五種形式:

c i w,表示ray 對於經過第i 座橋的愉悅度變成了w。

n u v,表示ray 對於經過景點u 到v 的路徑上的每一座橋的愉悅度都變成原來的相反數。

sum u v,表示詢問從景點u 到v 所獲得的總愉悅度。

max u v,表示詢問從景點u 到v 的路徑上的所有橋中某一座橋所提供的最大愉悅度。

min u v,表示詢問從景點u 到v 的路徑上的所有橋中某一座橋所提供的最小愉悅度。

測試資料保證,任意時刻,ray 對於經過每一座橋的愉悅度的絕對值小於等於1000。

輸出格式:

對於每乙個詢問(操作s、max 和min),輸出答案。

輸入樣例

3 0 1 1

1 2 2

8 sum 0 2

max 0 2

n 0 1

sum 0 2

min 0 2

c 1 3

sum 0 2

max 0 2

輸出樣例

3 2

1 -1 5 3

題目分析:

靜態處理順手就寫了樹鏈剖分

哪天比較閒的話在補一補lct的寫法

這題唯一需要注意的是取反操作

下放某個區間的取反標記

sum要取反

最大值與最小值交換再個自取反

sum[p]=-sum[p];

swap(maxn[p],minn[p]);

maxn[p]=-maxn[p];

minn[p]=-minn[p];

tag[p]^=1;

剩下的都是基本操作了

兩百多行真的累

#include

#include

#include

#include

#include

#include

using namespace std;

intread()

while(ss>='0'&&ss<='9')

return f*x;

}void print(int

x) if(x>9)print(x/10);

putchar(x

%10+'0');

}const int maxx=20010;

int n,m;

struct nodee[maxx*2];

int tot,head[maxx];

struct node2edge[maxx];

int dep[maxx],fa[maxx],son[maxx];

int top[maxx],size[maxx],d[maxx];

int num[maxx],pos[maxx<<2],cnt;

int sum[maxx<<2],maxn[maxx<<2],minn[maxx<<2],tag[maxx<<2];

char ss[5];

void add(int u,int v,int dis)

void dfs1(int u,int pa)

}void dfs2(int u,int tp)

}void up(int p,int

lc,int rc)

void push(int mid,int

lc,int rc,int p)//注意這裡的下放標記

}void build(int

s,int t,int p)

int mid=s+t>>1;

intlc=p<<1,rc=p<<1|1;

build(s,mid,lc);build(mid+1,t,rc);

up(p,lc,rc);

}int getsum(int ll,int rr,int

s,int t,int p)

int qsum()

if(u==v)return ans;

if(dep[u]>dep[v]) swap(u,v);

ans+=getsum(num[u]+1,num[v],1,n,1);

return ans;

}void update1(int u,int w,int

s,int t,int p)

int mid=s+t>>1;

intlc=p<<1,rc=p<<1|1;

push(mid,lc,rc,p);

if(u<=mid) update1(u,w,s,mid,lc);

else update1(u,w,mid+1,t,rc);

up(p,lc,rc);

}void change()

void update2(int ll,int rr,int

s,int t,int p)

int mid=s+t>>1;

intlc=p<<1,rc=p<<1|1;

push(mid,lc,rc,p);

if(ll<=mid) update2(ll,rr,s,mid,lc);

if(rr>mid) update2(ll,rr,mid+1,t,rc);

up(p,lc,rc);

}void uprange()

if(u==v)return;

if(dep[u]>dep[v]) swap(u,v);

update2(num[u]+1,num[v],1,n,1);

}int getmax(int ll,int rr,int

s,int t,int p)

int getmin(int ll,int rr,int

s,int t,int p)

int qmax()

if(u==v)return ans;

if(dep[u]>dep[v]) swap(u,v);

ans=max(ans,getmax(num[u]+1,num[v],1,n,1));

return ans;

}int qmin()

if(u==v)return ans;

if(dep[u]>dep[v]) swap(u,v);

ans=min(ans,getmin(num[u]+1,num[v],1,n,1));

return ans;

}int main()

dep[1]=1;

dfs1(1,-1);dfs2(1,1);

build(1,n,1);

m=read();

while(m--)

}return

0;}

P1505 國家集訓隊 旅遊 (樹鏈剖分)

傳送門 很明顯是樹鏈剖分,因為是邊權,所以將每個邊權給深度大的那個點可以了,根節點不用賦值,要求最大值和最小值,所以線段樹不包含根節點。因為點是從0編號的,所以父節點和重兒子陣列要初始化。include include include using namespace std const int n ...

樹鏈剖分 p1505 國家集訓隊 旅遊

ray 樂忠於旅遊,這次他來到了t 城。t 城是乙個水上城市,一共有 n 個景點,有些景點之間會用一座橋連線。為了方便遊客到達每個景點但又為了節約成本,t 城的任意兩個景點之間有且只有一條路徑。換句話說,t 城中只有n 1 座橋。ray 發現,有些橋上可以看到美麗的景色,讓人心情愉悅,但有些橋狹窄泥...

P1505 國家集訓隊 旅遊

題目鏈結 這道題其實還是比較好想的,同樣是邊權問題。我們需要維護最大值,最小值,和。最坑的地方就是路徑上的所有數變相反數,其實這個就是把區間和 1,區間最大 1,區間最小 1,最後pushdown的時候將取反標記 1,接下來一系列都是常規操作。而這裡還要記住,單點修改時也要下傳lazy標記。而我在跳...