題目:bzoj4034、洛谷p3178。
題目大意:有一棵點數為 n 的樹,以點 1 為根,且樹有點權。然後有 m 個操作,分為三種:
操作 1 :把某個節點 x 的點權增加 a 。
操作 2 :把某個節點 x 為根的子樹中所有點的點權都增加 a 。
操作 3 :詢問某個節點 x 到根的路徑中所有點的點權和。
現在要你輸出所有詢問的答案。
解題思路:對樹上的節點修改查詢,很容易想到樹鏈剖分。
單點修改就相當於只包含乙個節點的區間修改。
子樹修改,由於樹鏈剖分中一棵子樹的dfs序連續,相當於區間修改。
查詢就相當於多次區間查詢。
樹鏈剖分時間複雜度$o(n\log^2 n)$。
c++ code:
#include#include#include#define n 100005#define mem(a) memset(&a,0,sizeof a)
#define ll long long
int n,m,a[n],aa[n],dfn[n],idx,cnt,head[n],sz[n],fa[n],top[n],son[n],dep[n];
ll ans;
struct edgee[n<<1];
struct segmenttreenoded[n<<2];
inline int readint()
void dfs(int now)
}void dfs2(int now)
inline void pushdown(int len,int o)
void build(int l,int r,int o)
int mid=(l+r)>>1;
build(l,mid,o<<1);
build(mid+1,r,o<<1|1);
d[o].s=d[o<<1].s+d[o<<1|1].s;
}void add(int l,int r,int o,int l,int r,int k)
pushdown(r-l+1,o);
int mid=(l+r)>>1;
if(l<=mid)add(l,mid,o<<1,l,r,k);
if(mid>1;
if(l<=mid)query(l,mid,o<<1,l,r);
if(mid}void que(int x)
query(1,n,1,dfn[1],dfn[x]);
}int main();
head[u]=cnt;
e[++cnt]=(edge);
head[v]=cnt;
} fa[1]=top[1]=dep[1]=1;
dfs(1);dfs2(1);
for(int i=1;i<=n;++i)aa[dfn[i]]=a[i];
build(1,n,1);
while(m--)else
if(f==2)else
} return 0;
}
HAOI2015 樹上操作
題目描述 有一棵點數為 n 的樹,以點 1 為根,且樹點有邊權。然後有 m 個操作,分為三種 操作 1 把某個節點 x 的點權增加 a 操作 2 把某個節點 x 為根的子樹中所有點的點權都增加 a 操作 3 詢問某個節點 x 到根的路徑中所有點的點權和。輸入格式 第一行包含兩個整數 n,m 表示點數...
HAOI2015 樹上操作
有一棵點數為 n 的樹,以點 1 為根,且樹點有邊權。然後有 m 個操作,分為三種 操作 1 把某個節點 x 的點權增加 a 操作 2 把某個節點 x 為根的子樹中所有點的點權都增加 a 操作 3 詢問某個節點 x 到根的路徑中所有點的點權和。輸入格式 第一行包含兩個整數 n,m 表示點數和運算元。...
HAOI2015 樹上操作
嘟嘟嘟 樹剖自然可解,就是一道板子題,而且這道題還只問到根節點的距離是多少,而不是樹上任意兩點距離,就更方便了。1 include2 include3 include4 include5 include6 include7 include8 include9 include10 include11 ...