給出一棵樹,然後每個節點有乙個權值,代表這個點可以往上面跳多遠,問最少需要多少次可以跳出這顆樹
先dfs一次得到dfs序,然後按dfs序分塊。倍增計算從某點跳x到哪個點,用cn儲存它跳出這一塊需要的次數,ne儲存跳出這塊會去的點。然後塊內就暴力修改了。複雜度nsqrt(n);
#include #include#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using
namespace
std;
typedef
long
long
ll;typedef unsigned
long
long
ull;
#define ms(a, b) memset(a, b, sizeof(a))
#define pb push_back
#define mp make_pair
#define pii pair#define eps 0.0000000001
#define ios ios::sync_with_stdio(0);cin.tie(0);
#define random(a, b) rand()*rand()%(b-a+1)+a
#define pi acos(-1)
const ll inf =0x3f3f3f3f3f3f3f3fll;
const
int inf = 0x3f3f3f3f
;const
int maxn = 1e5 + 10
;const
int maxm = 200000 + 10
;const
int mod = 998244353
;int w[maxn],fa[20
][maxn],n,m;
inthead[maxn],nxt[maxn],to[maxn],tot;
int id[maxn],cnt;//
dfs序
int num,block,belong[maxn],l[maxn],r[maxn];//
塊的數目,快的大小,屬於那塊,每塊的左右邊界
int cn[maxn],ne[maxn],pre[maxn];//
跳出本塊的次數,跳向的下一塊的點,這個點會跳向的位置
void
init()
void addedge(int u,int
v)void dfs1(int u,int f)
}void build()
for(int i=1;i<=num;i++)
r[num]=n;
}int find(int u,int
l) }
returnu;}
void dfs2(int u)
}int query(int
u)
return
ans;
}void update(int u,int
val)
}}int
main()
for(int i=1;i<=n;i++)
dfs1(
1,0);
for(int i=1;i<20;i++)
}build();
dfs2(1);
scanf("%d
",&m);
while(m--)
else}}
return0;
}
HDU 5044 Tree 樹鏈剖分
題意 給一棵樹,兩種操作 add1 給u v路徑上所有點加上值k,add2 給u v路徑上所有邊加上k,初始值都為0,問最後每個點和每條邊的值,輸出。解法 樹鏈剖分可做,剖出來如果直接用線段樹來區間更新的話會tle,所以要換一種姿勢,有一種樹鏈剖分的經典姿勢就是看做樹狀陣列一樣,每次加值的時候,比如...
HDU 5044 Tree (樹鏈剖分)
這題用線段樹貌似過不了,和nyoj 的士兵殺敵五一樣,經過樹鏈剖分後,就把樹剖分成許多鏈,這樣可以對整個鏈操作,結合字首和的思想,如果某個節點到祖先節點更新這間的所有節點,可以把祖先節點 k 讓當前節點編號 1 減 k 這樣最後跑一邊陣列就可以了,葉子節點的時候類似。pragma comment l...
HDU5044 Tree 樹鏈剖分
大致題意 add1 u v u到v路徑上所有點的權值加上k,add2 u 到v路徑上所有邊的權值加上k 最後輸出所有點的權值,邊的權值。樹鏈剖分預處理然後來個線性o n 的操作。剛開始用線段樹tle了.1 pragma comment linker,stack 1024000000,10240000...