給一顆以1為根的樹。
每個點有兩個權值:vi, ti,一開始全部是零。
q次操作:
讀入o, u, d
o = 1 對u到根上所有點的vi += d
o = 2 對u到根上所有點的ti += vi * d
最後,輸出每個點的ti值(n, q <= 100000)
有50%的資料n,q <= 10000
注:所有數64位整數不會爆。
我們考慮用樹剖來做這道題。
對於乙個操作x,我們用樹鏈剖分,但現在問題來了,怎樣維護v和t呢?
我們對於線段樹的每一位存下乙個v,v1,t分別表示僅在該子樹擁有的操作1,該子樹及其父親傳下的操作1以及該子樹同時擁有t。每一次操作有乙個lzv,lzt表示懶標記下傳。下傳時v1 son+=lzv,lzv son+=lzv,t son+=t+lzt*v,lzt son+=t+lzt*v,最後把lzt,lzv,t清零。
#include
#include
#include
#include
#include
#define ll long long
using namespace std;
const int maxn=6e5+5;
struct codef[maxn];
int first[maxn],last[maxn],next[maxn],b[maxn],dfn[maxn],size[maxn],son[maxn],fa[maxn],top[maxn];
ll n,i,t,j,k,l,x,y,z,p,num,m,ans[maxn];
void lian(int
x,int
y)void dg(intx)}
void dg1(int
x)void make(int v)
void change(int l,int r,int v,int
x,int
y) if (l<=y && mid>=x) change(l,mid,v*2,x,y);
if (mid=x) change(mid+1,r,v*2+1,x,y);
}void find(int l,int r,int v)
find(l,mid,v*2);find(mid+1,r,v*2+1);
}int main()
find(1,n,1);
for (i=1;i<=n;i++)
printf("%lld\n",ans[i]);
}
51nod 1462 樹據結構
給出一棵n個點的樹,每個點有兩個權值v,t 有q個操作,有兩種操作 1.將x到根上的路徑上的點的v值都加上d 2.將x到根上的路徑上的點的t值都加上每個點的v值 d 最後求出所有點的t值 顯然可以直接樹鏈剖分做,不過lazy標記下放真麻煩,因為操作有互相影響 發現一種神標記方法 用矩陣 對於乙個點,...
51nod 1737 樹的重心
思路 樹的重心也叫樹的質心。找到乙個點,其所有的子樹中最大的子樹節點數最少,那麼這個點就是這棵樹的重心,刪去重心後,生成的多棵樹盡可能平衡。考慮每一條邊被統計進答案幾次,若斷開這條邊後樹形成大小為s1 s2的兩個聯通塊則這條邊最多被統計min s1,s2 次。刪去重心後任意同一聯通塊中的兩點不構成路...
51 nod 蘋果曼和樹
1500 蘋果曼和樹 基準時間限制 1 秒 空間限制 131072 kb 分值 80 難度 5 級演算法題 收藏 關注 蘋果曼有一棵 n個點的樹。有一些 至少乙個 結點被標記為黑色,有一些結點被標記為白色。現在考慮乙個包含 k 0 k n 條樹邊的集合。如果蘋果曼刪除這些邊,那麼會將這個樹分成 k ...