題目描述
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標記。而我在跳...