time limit: 10 sec memory limit: 162 mb
submit: 7568 solved: 3109
[submit][status][discuss]
description
一棵樹上有n個節點,編號分別為1到n,每個節點都有乙個權值w。我們將以下面的形式來要求你對這棵樹完成一些操作: i. change u t : 把結點u的權值改為t ii. qmax u v: 詢問從點u到點v的路徑上的節點的最大權值 iii. qsum u v: 詢問從點u到點v的路徑上的節點的權值和 注意:從點u到點v的路徑上的節點包括u和v本身
input
輸入的第一行為乙個整數n,表示節點的個數。接下來n – 1行,每行2個整數a和b,表示節點a和節點b之間有一條邊相連。接下來n行,每行乙個整數,第i行的整數wi表示節點i的權值。接下來1行,為乙個整數q,表示操作的總數。接下來q行,每行乙個操作,以「change u t」或者「qmax u v」或者「qsum u v」的形式給出。 對於100%的資料,保證1<=n<=30000,0<=q<=200000;中途操作中保證每個節點的權值w在-30000到30000之間。
output
對於每個「qmax」或者「qsum」的操作,每行輸出乙個整數表示要求輸出的結果。
sample input
1 22 3
4 14 2 1 3
qmax 3 4
qmax 3 3
qmax 3 2
qmax 2 3
qsum 3 4
qsum 2 1
change 1 5
qmax 3 4
change 3 6
qmax 3 4
qmax 2 4
qsum 3 4
sample output
樹鏈剖分的模板題,直接放**吧
#include
#include
#include
#include
using namespace std;
const int n=50010;
int tot=1,num=0,n,m,point[n],next[n*10],pos[n]=,siz[n]=,v[n]=;
int belong[n]=,fa[n][20]=,deep[n]=,map[n];
bool use[n];
char ch[10];
struct str[n*4];
struct caa[n*10];
inline void add(int i,int j)
inline void dfs1(int
x) for(i=point[x];i;i=next[i])
if(use[aa[i].en])
}inline void dfs2(int
x,int
y)inline int lca(int
x,int
y) if(x==y)return
x; else
return fa[x][0];
}#define mid (l+r)/2
#define l k<<1,l,mid
#define r k<<1|1,mid+1,r
inline void build(int k,int l,int r)
build(l);build(r);
tr[k].maxn=max(tr[k<<1].maxn,tr[k<<1|1].maxn);
tr[k].sum=tr[k<<1].sum+tr[k<<1|1].sum;
}void insert(int k,int l,int r,int
x,int
y) if(x
<=mid) insert(l,x,y);
else insert(r,x,y);
tr[k].maxn=max(tr[k<<1].maxn,tr[k<<1|1].maxn);
tr[k].sum=tr[k<<1].sum+tr[k<<1|1].sum;
}inline int qurry(int k,int l,int r,int
x,int
y,int kind)
if(y>mid)
return kind==0?maxn:sum;
}inline int ask(int
x,int
y,int kind)
if(kind==0) maxn=max(maxn,qurry(1,1,n,pos[y],pos[x],kind));
else sum+=qurry(1,1,n,pos[y],pos[x],kind);
return kind==0?maxn:sum;
}int main()
for(i=1;i<=n;++i) scanf("%d",&v[i]);
dfs1(1);
dfs2(1,1);
build(1,1,n);
scanf("%d",&m);
while(m--)
}}
time limit: 10 sec memory limit: 256 mb
submit: 369 solved: 151
[submit][status][discuss]
description
有一棵點數為 n 的樹,以點 1 為根,且樹點有邊權。然後有 m 個
操作,分為三種:
操作 1 :把某個節點 x 的點權增加 a 。
操作 2 :把某個節點 x 為根的子樹中所有點的點權都增加 a 。
操作 3 :詢問某個節點 x 到根的路徑中所有點的點權和。
input
第一行包含兩個整數 n, m 。表示點數和運算元。
接下來一行 n 個整數,表示樹中節點的初始權值。
接下來 n-1 行每行三個正整數 fr, to , 表示該樹中存在一條邊 (fr, to) 。
再接下來 m 行,每行分別表示一次操作。其中第乙個數表示該操
作的種類( 1-3 ) ,之後接這個操作的引數( x 或者 x a ) 。
output
對於每個詢問操作,輸出該詢問的答案。答案之間用換行隔開。
sample input
5 51 2 3 4 5
1 21 4
2 32 5
3 31 2 1
3 52 1 2
3 3
sample output
hint
對於 100% 的資料, n,m<=100000 ,且所有輸入資料的絕對值都不
#include
#include
#include
#include
using
namespace
std;
const
int n=100100;
int point[n],next[n*4],belong[n],siz[n],son[n],pos[n],deep[n];
int n,m,tot=1,num=0,fa[n];
long
long tr[n*4],de[n*4],r[n];
bool use[n];
struct saa[n*4];
inline
void add(int x,int y)
inline
void dfs_1(int x)
}inline
void dfs_2(int x,int y)
inline
void pushdown(int k,int l,int r)
inline
void insert(int k,int l,int r,int x,long
long y)
pushdown(k,l,r);
if(x<=mid) insert(l,x,y);
else insert(r,x,y);
tr[k]=tr[k<<1]+tr[k<<1|1];
}inline
void change(int k,int l,int r,int x,int y,long
long z)
pushdown(k,l,r);
if(x<=mid) change(l,x,y,z);
if(y>mid) change(r,x,y,z);
tr[k]=tr[k<<1]+tr[k<<1|1];
}inline
long
long qurey(int k,int l,int r,int x,int y)
inline
long
long ask(int x,int y)
sum+=qurey(1,1,n,pos[y],pos[x]);
return sum;
}int main()
dfs_1(1);
dfs_2(1,1);
for(i=1;i<=n;++i)
while(m--)
else
}}
HDU3966 樹鏈剖分(點權)入門 鏈分治
本人的第二道樹鏈剖分。題意 n個結點的樹,每個結點有個權值,3個操作 1 增加u到v的路徑上所有結點的權值 2 減少u到v的路徑上所有結點的權值 3 查詢某個結點的權值 如下 pragma comment linker,stack 100000000,100000000 include includ...
HYSBZ 2243 染色 樹鏈剖分 點上剖分
題意 兩種操作 1.修改u到v路徑上的點的顏色為c 2.詢問u到v路徑上有多少段顏色 線段樹上用區間合併來維護答案 主要是在詢問時要考慮一下,維護上個段的最後節點顏色來維護顏色段數 include define sf scanf define pf printf using namespace st...
樹鏈剖分邊權轉化為點權
現在給出將樹鏈剖分上的邊權轉化為點權的方法 也就是將邊權轉到它下方的點去 我們通過畫圖可以發現,這樣的話,我們會多算最近公共祖先上方的點 方法一 先不考慮的多算的部分,還按原來的方法來,在之後消除最近公共祖先的影響 我們只需要在原來的 基礎上將 query path 改成 long long que...