生活随笔
收集整理的這篇文章主要介紹了
hdu 6962 I love tree 线段树维护二次函数
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
傳送門
文章目錄
題意:
給你nnn個點的一顆樹,有mmm次詢問,每次詢問有兩個操作:
(1)(1)(1)將[a,b][a,b][a,b]路徑上的點依次加上12,22,32,...,len2,len=path(a,b)1^2,2^2,3^2,...,len^2,len=path(a,b)12,22,32,...,len2,len=path(a,b)。
(2)(2)(2)詢問xxx點的值。
思路:
先考慮在線性的情況下如何實現兩個操作。
不難發現,直接修改的瓶頸是不能確保每次修改的都一樣,但是發現我們最終查詢的時候只是單點查詢,所以我們可以考慮將每個點的值作為變量,讓后維護常量。
通過以上分析,我們可以考慮將操作111轉換成二次函數,比如當前要加區間[l,r][l,r][l,r],那么就相當于加上一個(x?l)2(x-l)^2(x?l)2的二次函數,其中x∈[l+1,r+1]x\in [l+1,r+1]x∈[l+1,r+1],將其展開x2+l2?2?x?lx^2+l^2-2*x*lx2+l2?2?x?l,顯然我們可以分別對三個系數單獨維護,即1,l2,2l1,l^2,2l1,l2,2l,也就是線段樹區間修改的過程,之后查詢的時候乘上對應的位置即可。
那么在樹上怎么求呢?顯然只需要一個樹剖即可,樹剖將其分成lognlognlogn段區間每段區間都是連續的,所以注意一下細節直接寫就好啦。
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#include<random>
#include<cassert>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define pb push_back
#define mk make_pair
#define Mid ((tr[u].l+tr[u].r)>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
using namespace std
;
typedef long long LL
;
typedef unsigned long long ULL
;
typedef pair
<int,int> PII
;const int N
=1000010,mod
=1e9+7,INF
=0x3f3f3f3f;
const double eps
=1e-6;int n
;
vector
<int>v
[N
];
int fa
[N
],depth
[N
],se
[N
],son
[N
],dfn
[N
],tot
,top
[N
];struct Seg {struct Node {int l
,r
;LL sum
,lazy
;}tr
[N
<<2];void pushup(int u
) {tr
[u
].sum
=tr
[L
].sum
+tr
[R
].sum
;}void pushdown(int u
) {LL lazy
=tr
[u
].lazy
; tr
[u
].lazy
=0;tr
[L
].sum
+=lazy
*Len(L
); tr
[L
].lazy
+=lazy
;tr
[R
].sum
+=lazy
*Len(R
); tr
[R
].lazy
+=lazy
;}void build(int u
,int l
,int r
) {tr
[u
]={l
,r
};if(l
==r
) return;build(L
,l
,Mid
); build(R
,Mid
+1,r
);}void change(int u
,int l
,int r
,LL sum
) {if(tr
[u
].l
>=l
&&tr
[u
].r
<=r
) {tr
[u
].sum
+=Len(u
)*sum
;tr
[u
].lazy
+=sum
;return ;}pushdown(u
);if(l
<=Mid
) change(L
,l
,r
,sum
);if(r
>Mid
) change(R
,l
,r
,sum
);}LL
query(int u
,int pos
) {if(tr
[u
].l
==tr
[u
].r
) return tr
[u
].sum
;pushdown(u
);if(pos
<=Mid
) return query(L
,pos
);else return query(R
,pos
);}
}t1
,t2
,t3
;void dfs1(int u
,int f
) {depth
[u
]=depth
[f
]+1; fa
[u
]=f
;se
[u
]=1;for(auto x
:v
[u
]) {if(x
==f
) continue;dfs1(x
,u
);se
[u
]+=se
[x
];if(se
[x
]>se
[son
[u
]]) son
[u
]=x
;}
}void dfs2(int u
,int t
) {top
[u
]=t
; dfn
[u
]=++tot
;if(son
[u
]) dfs2(son
[u
],t
);for(auto x
:v
[u
]) {if(x
==son
[u
]||x
==fa
[u
]) continue;dfs2(x
,x
);}
}void change(int x
,int y
,int cnt
) {int l
=1,r
=cnt
;while(top
[x
]!=top
[y
]) {if(depth
[top
[x
]]>depth
[top
[y
]]) {LL add
=dfn
[x
]+l
; l
+=depth
[x
]-depth
[top
[x
]]+1;t1
.change(1,dfn
[top
[x
]],dfn
[x
],1);t2
.change(1,dfn
[top
[x
]],dfn
[x
],add
*add
);t3
.change(1,dfn
[top
[x
]],dfn
[x
],add
);x
=fa
[top
[x
]];} else {int now
=depth
[y
]-depth
[top
[y
]]+1;LL add
=dfn
[top
[y
]]+(r
-now
-1); r
-=now
;t1
.change(1,dfn
[top
[y
]],dfn
[y
],1);t2
.change(1,dfn
[top
[y
]],dfn
[y
],add
*add
);t3
.change(1,dfn
[top
[y
]],dfn
[y
],add
);y
=fa
[top
[y
]];}}if(depth
[x
]>depth
[y
]) {LL add
=dfn
[x
]+l
; l
+=depth
[x
]-depth
[y
]+1;t1
.change(1,dfn
[y
],dfn
[x
],1);t2
.change(1,dfn
[y
],dfn
[x
],add
*add
);t3
.change(1,dfn
[y
],dfn
[x
],add
);} else {int now
=depth
[y
]-depth
[x
]+1;LL add
=dfn
[x
]-(r
-now
+1); r
-=now
;t1
.change(1,dfn
[x
],dfn
[y
],1);t2
.change(1,dfn
[x
],dfn
[y
],add
*add
);t3
.change(1,dfn
[x
],dfn
[y
],add
);}
}int lca(int x
,int y
) {while(top
[x
]!=top
[y
]) {if(depth
[top
[x
]]<depth
[top
[y
]]) swap(x
,y
);x
=fa
[top
[x
]];}if(depth
[x
]<depth
[y
]) return x
;else return y
;
}int main()
{
scanf("%d",&n
);for(int i
=1;i
<=n
-1;i
++) {int a
,b
; scanf("%d%d",&a
,&b
);v
[a
].pb(b
); v
[b
].pb(a
);}dfs1(1,0); dfs2(1,1);t1
.build(1,1,n
); t2
.build(1,1,n
); t3
.build(1,1,n
);int m
; scanf("%d",&m
);while(m
--) {int op
,x
,y
;scanf("%d%d",&op
,&x
);if(op
==1) {scanf("%d",&y
);change(x
,y
,depth
[x
]+depth
[y
]-2*depth
[lca(x
,y
)]+1);} else {printf("%lld\n",t1
.query(1,dfn
[x
])*dfn
[x
]*dfn
[x
]+t2
.query(1,dfn
[x
])-2*dfn
[x
]*t3
.query(1,dfn
[x
]));}}return 0;
}
總結
以上是生活随笔為你收集整理的hdu 6962 I love tree 线段树维护二次函数的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。