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,所以要換一種姿勢,有一種樹鏈剖分的經典姿勢就是看做樹狀陣列一樣,每次加值的時候,比如...