日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

hdu 3966( 树链剖分+点权更新)

發布時間:2025/3/16 编程问答 16 豆豆
生活随笔 收集整理的這篇文章主要介紹了 hdu 3966( 树链剖分+点权更新) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題意:給一棵樹,并給定各個點權的值,然后有3種操作:

I C1 C2 K: 把C1與C2的路徑上的所有點權值加上K

D C1 C2 K:把C1與C2的路徑上的所有點權值減去K

Q C:查詢節點編號為C的權值


解題思路:這道題是明顯的樹鏈剖分問題,只是這里是點權更新,注意與邊權更新的不同,剩下的基本是模板了。


#include<iostream> #include<cstdio> #include<cstring> using namespace std;const int maxn = 50010; struct Segment {int l,r,sum,lazy; }tree[maxn<<2]; struct Edge {int to,next; }edge[maxn<<1]; int n,m,p,cnt,num,pre[maxn],A[maxn]; int top[maxn],son[maxn],size[maxn]; int fa[maxn],idx[maxn],dep[maxn];void addedge(int u,int v) {edge[cnt].to = v;edge[cnt].next = pre[u];pre[u] = cnt++; }void dfs(int u) {size[u] = 1; son[u] = 0;int tmp = 0;for(int i = pre[u]; i != -1; i = edge[i].next){int v = edge[i].to;if(fa[u] == v) continue;fa[v] = u;dep[v] = dep[u] + 1;dfs(v);size[u] += size[v];if(size[v] > tmp){tmp = size[v];son[u] = v;}} }void build_tree(int u,int tp) {idx[u] = ++num; top[u] = tp;if(son[u] != 0) build_tree(son[u],tp);for(int i = pre[u]; i != -1; i = edge[i].next){int v = edge[i].to;if(fa[u] == v || son[u] == v) continue;build_tree(v,v);} }void build_Segment(int rt,int l,int r) {tree[rt].l = l, tree[rt].r = r;tree[rt].sum = tree[rt].lazy = 0;if(l == r) return;int mid = (l + r) >> 1;build_Segment(rt<<1,l,mid);build_Segment(rt<<1|1,mid+1,r); }void PushDown(int rt) {if(tree[rt].lazy != 0){tree[rt<<1].lazy += tree[rt].lazy;tree[rt<<1].sum += tree[rt].lazy;tree[rt<<1|1].lazy += tree[rt].lazy;tree[rt<<1|1].sum += tree[rt].lazy;tree[rt].lazy = 0;} }void PushUp(int rt) {tree[rt].sum = tree[rt<<1].sum + tree[rt<<1|1].sum; }void update(int rt,int l,int r,int val) {if(l <= tree[rt].l && tree[rt].r <= r){tree[rt].sum += val;tree[rt].lazy += val;return;}PushDown(rt);int mid = (tree[rt].l + tree[rt].r) >> 1;if(l <= mid) update(rt<<1,l,r,val);if(mid < r) update(rt<<1|1,l,r,val);PushUp(rt); }int query(int rt,int pos) {if(tree[rt].l == tree[rt].r)return tree[rt].sum;PushDown(rt);int mid = (tree[rt].l + tree[rt].r) >> 1;if(pos <= mid) return query(rt<<1,pos);else return query(rt<<1|1,pos); }void Modify(int a,int b,int val) {int f1 = top[a], f2 = top[b];while(f1 != f2){if(dep[f1] < dep[f2]){swap(f1,f2);swap(a,b);}update(1,idx[f1],idx[a],val);a = fa[f1], f1 = top[a];}if(dep[a] > dep[b]) swap(a,b);update(1,idx[a],idx[b],val); }int main() {int u,v,val;char op[2];while(scanf("%d%d%d",&n,&m,&p)!=EOF){memset(pre,-1,sizeof(pre));cnt = num = 0;dep[1] = 0;for(int i = 1; i <= n; i++)scanf("%d",&A[i]);for(int i = 1; i <= m; i++){scanf("%d%d",&u,&v);addedge(u,v);addedge(v,u);}dfs(1);build_tree(1,1);build_Segment(1,1,num);for(int i = 1; i <= n; i++)update(1,idx[i],idx[i],A[i]);while(p--){getchar();scanf("%s",op);if(op[0] == 'I'){scanf("%d%d%d",&u,&v,&val);Modify(u,v,val);}else if(op[0] == 'D'){scanf("%d%d%d",&u,&v,&val);Modify(u,v,-val);}else{scanf("%d",&u);printf("%d\n",query(1,idx[u]));}}}return 0; }

總結

以上是生活随笔為你收集整理的hdu 3966( 树链剖分+点权更新)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。