传送门
文章目录
- 题意:
- 思路:
题意:
给你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段区间每段区间都是连续的,所以注意一下细节直接写就好啦。
//#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native")
//#pragma GCC optimize(2)
#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;//void rd_cre() { freopen("d://dp//data.txt","w",stdout); srand(time(NULL)); }
//void rd_ac() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//AC.txt","w",stdout); }
//void rd_wa() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//WA.txt","w",stdout); }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);// pushup(u);}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);// pushup(u);}
}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()
{
// ios::sync_with_stdio(false);
// cin.tie(0);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 {//if(x==2) cout<<t3.query(1,dfn[x])<<"**"<<endl;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;
}
/**/