【樹鏈剖分】Codechef DGCD
題意:
給出一棵點權樹,有M次操作:
1、詢問一條路徑上的GCD
2、將一段路徑上的點權加上d
分析:
如果這題在一個序列上就非常美妙了:
利用輾轉相減法:
所以如果這個問題在一個序列上:
設為
就可以利用差分,變為:
此時的區間修改就變為兩次單點修改了。
現在把這個問題轉移到樹上。。。。就很板了。。。
直接樹鏈剖分,然後對每個鏈,當成一個序列來做。
然後修改的時候注意一下就行了(笑)。
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#define SF scanf
#define PF printf
#define MAXN 50010
using namespace std;
int dep[MAXN],son[MAXN],fa[MAXN],sz[MAXN],tid[MAXN],rnk[MAXN],top[MAXN],v[MAXN];
int tree[MAXN*4],tag[MAXN*4];
int n,dcnt;
vector<int> a[MAXN];
int gcd(int x,int y){
if(y==0)
return x;
return gcd(y,x%y);
}
void dfs1(int x,int fax){
dep[x]=dep[fax]+1;
fa[x]=fax;
son[x]=-1;
sz[x]=1;
for(int i=0;i<int(a[x].size());i++){
int u=a[x][i];
if(u==fax)
continue;
dfs1(u,x);
sz[x]+=sz[u];
if(son[x]==-1||sz[son[x]]<sz[u])
son[x]=u;
}
}
void dfs2(int x,int tp){
top[x]=tp;
tid[x]=++dcnt;
rnk[dcnt]=x;
if(son[x]==-1)
return ;
dfs2(son[x],tp);
for(int i=0;i<a[x].size();i++){
int u=a[x][i];
if(u==fa[x]||u==son[x])
continue;
dfs2(u,u);
}
}
void build(int l=1,int r=n,int id=1){
if(l==r){
if(top[rnk[l]]!=rnk[l])
tree[id]=v[fa[rnk[l]]]-v[rnk[l]];
else
tree[id]=v[rnk[l]];
return ;
}
int mid=(l+r)>>1;
build(l,mid,id<<1);
build(mid+1,r,id<<1|1);
tree[id]=gcd(tree[id<<1],tree[id<<1|1]);
}
void change_on_point(int pos,int val,int l=1,int r=n,int id=1){
if(l==r){
tree[id]+=val;
return ;
}
int mid=(l+r)>>1;
if(pos<=mid)
change_on_point(pos,val,l,mid,id<<1);
else
change_on_point(pos,val,mid+1,r,id<<1|1);
tree[id]=gcd(tree[id<<1],tree[id<<1|1]);
}
void change_on_road(int l1,int r1,int val,int l=1,int r=n,int id=1){
if(l>=l1&&r<=r1){
tag[id]+=val;
return ;
}
int mid=(l+r)>>1;
if(l1<=mid)
change_on_road(l1,r1,val,l,mid,id<<1);
if(r1>mid)
change_on_road(l1,r1,val,mid+1,r,id<<1|1);
}
int query_on_point(int pos,int l=1,int r=n,int id=1){
if(l==r)
return v[rnk[l]]+tag[id];
int mid=(l+r)>>1;
if(pos<=mid)
return query_on_point(pos,l,mid,id<<1)+tag[id];
else
return query_on_point(pos,mid+1,r,id<<1|1)+tag[id];
}
int query_on_road(int l1,int r1,int l=1,int r=n,int id=1){
if(l>=l1&&r<=r1)
return tree[id];
int mid=(l+r)>>1;
int res1=0,res2=0;
if(l1<=mid)
res1=query_on_road(l1,r1,l,mid,id<<1);
if(r1>mid)
res2=query_on_road(l1,r1,mid+1,r,id<<1|1);
return gcd(res1,res2);
}
void change_on_tree(int u,int v,int val){
if(u==v){
if(top[u]!=u)
change_on_point(tid[u],-val);
else
change_on_point(tid[u],val);
if(son[u]!=-1)
change_on_point(tid[son[u]],val);
change_on_road(tid[u],tid[u],val);
return ;
}
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]])
swap(u,v);
change_on_road(tid[top[u]],tid[u],val);
change_on_point(tid[top[u]],val);
if(son[u]!=-1)
change_on_point(tid[son[u]],val);
u=fa[top[u]];
}
if(dep[u]>dep[v])
swap(u,v);
change_on_road(tid[u],tid[v],val);
if(top[u]!=u)
change_on_point(tid[u],-val);
else
change_on_point(tid[u],val);
if(son[v]!=-1)
change_on_point(tid[son[v]],val);
}
int query_on_tree(int u,int v){
if(u==v)
return query_on_point(tid[u]);
int res=0;
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]])
swap(u,v);
res=gcd(res,query_on_road(tid[top[u]],tid[u]));
u=fa[top[u]];
}
if(dep[u]>dep[v])
swap(u,v);
if(u!=v)
res=gcd(res,query_on_road(tid[u]+1,tid[v]));
res=gcd(res,query_on_point(tid[u]));
return res;
}
char s[20];
int main(){
SF("%d",&n);
int x,y,val;
for(int i=1;i<n;i++){
SF("%d%d",&x,&y);
x++;
y++;
a[x].push_back(y);
a[y].push_back(x);
}
for(int i=1;i<=n;i++)
SF("%d",&v[i]);
dfs1(1,0);
dfs2(1,1);
build();
int m;
SF("%d",&m);
for(int i=1;i<=m;i++){
SF("%s",s);
if(s[0]=='F'){
SF("%d%d",&x,&y);
x++,y++;
PF("%d\n",abs(query_on_tree(x,y)));
}
else{
SF("%d%d%d",&x,&y,&val);
x++,y++;
change_on_tree(x,y,val);
}
}
}
順便提供資料生成器:
#include<cstdio>
#include<cstdlib>
#include<ctime>
#define SF scanf
#define PF printf
#define MAXN 20
#define MAXM 20
#define MAXV 20
using namespace std;
int get_rand(int x)
相關推薦
【樹鏈剖分】Codechef DGCD
題意:
給出一棵點權樹,有M次操作: 1、詢問一條路徑上的GCD 2、將一段路徑上的點權加上d
分析:
如果這題在一個序列上就非常美妙了: 利用輾轉相減法:
G
【樹鏈剖分】洛谷P3379 樹鏈剖分求LCA
pri else ios class 論文 main 我們 嚴格 所有 題目描述
如題,給定一棵有根多叉樹,請求出指定兩個點直接最近的公共祖先。
輸入輸出格式
輸入格式:
第一行包含三個正整數N、M、S,分別表示樹的結點個數、詢問的個數和樹根結點的序號。
接下來N-1行
4034. [HAOI2015]樹上操作【樹鏈剖分】
uil hint scanf -m oid 輸入數據 content 其中 HA Description
有一棵點數為 N 的樹,以點 1 為根,且樹點有邊權。然後有 M 個
操作,分為三種:
操作 1 :把某個節點 x 的點權增加 a 。
操作 2 :把某個節
3999. [TJOI2015]旅遊【樹鏈剖分】
== urn ati hang script 線段樹 城市編號 turn esc Description
為了提高智商,ZJY準備去往一個新世界去旅遊。這個世界的城市布局像一棵樹。每兩座城市之間只有一條路徑可
以互達。每座城市都有一種寶石,有一定的價格。ZJY為了賺
LOJ2269 [SDOI2017] 切樹遊戲 【FWT】【動態DP】【樹鏈剖分】【線段樹】
stack dep 根據 註意 樹形dp 沒有 top cto HERE 題目分析:
好題。本來是一道好的非套路題,但是不湊巧的是當年有一位國家集訓隊員正好介紹了這個算法。
首先考慮靜態的情況。這個的DP方程非常容易寫出來。
接著可以註意到對於異或結果的計數可以看成一個F
bzoj [Usaco2010 Hol]cowpol 奶牛政壇【樹鏈剖分】
clu int == fat void += char tdi ios 意識流虛樹
首先考慮只有一個黨派,那麽可以O(n)求樹的直徑,步驟是隨便指定一個根然後找距離根最遠點,然後再找距離這個最遠點最遠的點,那麽最遠點和距離這個最遠點最遠的點之間的距離就是直徑
那麽考慮多黨派
UOJ268 [清華集訓2016] 數據交互 【動態DP】【堆】【樹鏈剖分】【線段樹】
auto 合並 -s 樹形dp lazy tail clas 記錄 less 題目分析:
不難發現可以用動態DP做。
題目相當於是要我求一條路徑,所有與路徑有交的鏈的代價加入進去,要求代價最大。
我們把鏈的代價分成兩個部分:一部分將代價加入$LCA$之中,用$g$數組保存;
【洛谷P3038 [USACO11DEC]牧草種植】【樹鏈剖分】【裸】【邊權修改與查詢】
【連結】
https://www.luogu.org/problemnew/show/P3038
【題意】
給出一棵n個節點的樹,有m個操作,操作為將一條路徑上的邊權加一或詢問某條邊的權值。
【思路】
樹鏈剖分的裸題。
但是這個題是在邊上進行操作,我們考慮把邊上的操作轉移到點
BZOJ1036樹的統計【樹鏈剖分】
Description
一棵樹上有n個節點,編號分別為1到n,每個節點都有一個權值w。我們將以下面的形式來要求你對這棵樹完成 一些操作: I. CHANGE u t : 把結點u的權值改為t II. QMAX u v: 詢問從點u到點v的路徑上的節點的最大權值 I II. QSUM u v:
[JZOJ5909]【NOIP2018模擬10.16】跑商【圓方樹】【樹鏈剖分】
Description
基三的地圖可以看做 n 個城市,m 條邊的無向圖,尊者神高達會從某個點出發並在起點購買貨物,在旅途中任意一點賣出並最終到達終點,尊者神高達的時間很寶貴,所以他不會重複經過同一個城市,但是為了掙錢,他可能會去繞路。當然,由於工作室氾濫,所以一個城市的貨物
Jiu Yuan Wants to Eat【2018焦作網路賽】【樹鏈剖分】
題目連結
樹鏈剖分學習筆記,可以看這裡
這道題還真挺好的,以前不會做,現在想了發現,學過樹鏈剖分之後,剩下的部分就是處理去反那塊比較的不容易些了,但是想了一下午,現在還是給我敲出來了,我們主要難處理的就是關於求反,那麼怎麼處理求反?
一開始讀題的時候,我還
Aragorn's Story 【HDU - 3966】【樹鏈剖分】
題目連結
樹鏈剖分的學習筆記(更新中)
這道題所給的Hint好有迷惑性,它跟我們說注意士兵的數量可能為負數,我的第一反應是,士兵的數量是不是不能為負數,那麼我們是不是要做出些什麼調整,然而,語文不好的我看了Discuss才知道說的是:士兵的數量可以為負數。這樣也好,題目就變
【樹鏈剖分】樹上的詢問
【題目描述】
給你一棵具有N個點(編號為1到N)M條邊的樹,並給定各個點權的值,然後有3種操作:
I C1 C2 K:把C1與C2的路徑上的所有點權值加上K
D C1 C2 K:把C1與
【洛谷P3379】【lca】【樹鏈剖分】
【連結】
【題意】
求lca
【程式碼】
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 6;
vector<int>v[maxn];
int a[ma
2018 Multi-University Training Contest 7 1008 Traffic Network in Numazu【樹鏈剖分】
題意:NN個節點NN條邊的連通圖,有刪改操作和線上查詢兩點間的最短路。
分析:相當於是一顆樹上多了一條邊,那麼找到一條這樣的邊(滿足刪除之後餘下整體為樹)把它刪掉。對於兩點間的查詢,由於有修改,就採用樹鏈剖分跑線段樹的方法來解決就OK。最後在計算答案的時候
校內賽 codeforces 827D【最小生成樹】【樹鏈剖分】 解題報告
找不到題面!!
題意
給出一張n(<=2e5)個點 m(<=2e5)條邊無向圖,保證有生成樹。對於每條邊,給出一個最大值maxLength,咦即能夠保證這條邊能夠出現在所有的最小生成樹中,邊權的最大值為maxLength(同時,其他所有邊長度不變
【Codeforces】【網路流】【樹鏈剖分】【線段樹】ALT (CodeForces - 786E)
題意
現在有m個人,每一個人都特別喜歡狗。另外還有一棵n個節點的樹。 現在每個人都想要從樹上的某個節點走到另外一個節點,且滿足要麼這個人自帶一條狗m,要麼他經過的所有邊h上都有一條狗。 2<=n<=2*10^4,1<=m<=10^4
輸入格式
第一行為兩個整數n,m,分
BZOJ2434 [NOI2011] 阿狸的打字機 【樹鏈剖分】【線段樹】【fail樹】【AC自動機】
題目分析:
畫一下fail樹,就會發現就是x的子樹中屬於y路徑的,把y剖分一下,用線段樹處理
$O(n*log^2 n)$。
程式碼:
1 #include<bits/stdc++.h>
2 using namespace std;
3
4 const int ma
【bzoj1036】樹的統計Count【樹鏈剖分】【ZKW大法好】【卡常大法好】
關於這個樹上路徑端點會重合的問題,我們只要不判斷x==y就行了。詳見被註釋呵呵的地方。
#include<cstdio>
#include<cstring>
#include<iostream>
using namesp
ACM-ICPC 2018 焦作賽區網路預賽 E Jiu Yuan Wants to Eat【樹鏈剖分】
Jiu Yuan Wants to Eat
Time Limit: 3000 MS Memory Limit: 65536 K Problem Description
You ye Jiu yuan is the daughter of the Great G