HDU 6547 Tree 樹鏈剖分 線段樹

2021-09-25 06:43:27 字數 1683 閱讀 6386

hdu---6547:tree

給定一顆樹,q次操作,(1)詢問樹上任意兩點之間最短路上點權和(2)將樹上任意兩點之間最短路上每個點權開根

樹上路徑問題樹鏈剖分跑不了,考慮怎樣維護區間開根,容易發現0,1開根後不改變值;開根遞減的很快,1e9開5次根後再開根就不變了,那麼就可以每次暴力更新到葉子節點,並且標記當前子樹是否全為0或1,每個葉子節點最多訪問5次

#include using namespace std;

typedef long long ll;

const int maxn = 2e5+255;

const int maxm = 1e6+16;

int n,q,u,v,op,a[maxn],cnt,tt,head[maxn];

struct edgee[maxn<<1];

inline int read()

inline void write(ll x)

inline void addedge(int u,int v);

head[u] = cnt;

}int d[maxn],f[maxn],sz[maxn],son[maxn],st[maxn],ed[maxn],b[maxn];

void dfs1(int x,int fa,int depth)

ed[x] = ++tt; b[tt] = x;

}int rk[maxn],id[maxn],top[maxn],num;

void dfs2(int x,int top)

}/*************以上為樹鏈剖分*************/

ll tr[maxn<<2];

int tag[maxn<<2];

void build(int l,int r,int x)

int mid = (l+r)>>1;

build(l,mid,x<<1);

build(mid+1,r,x<<1|1);

tr[x] = tr[x<<1] + tr[x<<1|1];

}void updata(int l,int r,int l,int r,int x)

int mid = (l+r) >> 1;

updata(l,mid,l,r,x<<1);

updata(mid+1,r,l,r,x<<1|1);

tr[x] = tr[x<<1] + tr[x<<1|1];

tag[x] = (tag[x<<1]&tag[x<<1|1]);

}void query(int l,int r,int l,int r,int x,ll &sum)

int mid = (l+r)>>1;

query(l,mid,l,r,x<<1,sum);

query(mid+1,r,l,r,x<<1|1,sum);

}void updatapath(int u,int v)

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

updata(1,n,id[u],id[v],1);

}ll querypath(int u,int v)

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

query(1,n,id[u],id[v],1,sum);

return sum;

}int main()

return 0;

}

HDU 6547 樹鏈剖分

wls 有三棵樹,樹上每個節點都有乙個值 aiai,現在有 2 種操作 1.將一條鏈上的所有節點的值開根號向下取整 2.求一條鏈上值的和 鏈的定義是兩點之間的最短路。input 第一行兩個數 nn,qq 分別代表樹上點的數量和運算元量。第二行 nn 個整數,第 ii 個數代表第 ii 個點的值 ai...

HDU 6547 樹鏈剖分

大意是一顆有根樹,根節點為1,樹上有兩個操作,乙個是對兩個節點間的節點開根號,乙個是詢問兩個節點間所有節點的權值和 開根號就是暴力對每個節點開根號 因為開根號能很快的接近1 樹鏈剖分解決樹上問題就是把它轉化成線性表,然後再用一些資料結構維護一下就好了。所以說線性表的的增刪查改才是重點 ac incl...

HDU 5044 Tree 樹鏈剖分

題意 給一棵樹,兩種操作 add1 給u v路徑上所有點加上值k,add2 給u v路徑上所有邊加上k,初始值都為0,問最後每個點和每條邊的值,輸出。解法 樹鏈剖分可做,剖出來如果直接用線段樹來區間更新的話會tle,所以要換一種姿勢,有一種樹鏈剖分的經典姿勢就是看做樹狀陣列一樣,每次加值的時候,比如...