洛谷 P3676 小清新数据结构题
https://www.luogu.org/problemnew/show/P3676
这题被我当成动态dp去做了,码了4k,搞了一个换根的动态dp
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
struct E
{
int to,nxt;
}e[];
int f1[],ne;
struct P1
{
int len;ll a,b,c,d,e,f;
//长度,(点权)和,后缀和之和,后缀和的平方之和,(答案)和
//前缀和之和,前缀和的平方之和
};
struct P2
{
ll a,b;
//点权和,答案和
};
ll a[];
int sz[],hson[],ff[];
int b[],pl[];
int n,m;
inline void merge(P1 &c,const P1 &a,const P1 &b)
{
c.len=a.len+b.len;
c.a=a.a+b.a;
c.b=b.b+a.b+b.a*a.len;
c.c=b.c+b.a*b.a*a.len+*a.b*b.a+a.c;
c.d=a.d+b.d;
c.e=a.e+b.e+a.a*b.len;
c.f=a.f+a.a*a.a*b.len+*b.e*a.a+b.f;
}
inline void initnode(P1 &c,const P2 &a)
{
c.len=;c.a=c.b=c.e=a.a;c.c=c.f=a.a*a.a;c.d=a.b;
}
namespace S
{
#define lc (num<<1)
#define rc (num<<1|1)
P1 d[];
inline void upd(int num){merge(d[num],d[lc],d[rc]);}
P1 x;int L;
void _setx(int l,int r,int num)
{
if(l==r)
{
d[num]=x;
return;
}
int mid=(l+r)>>;
if(L<=mid) _setx(l,mid,lc);
else _setx(mid+,r,rc);
upd(num);
}
P1 getx(int L,int R,int l,int r,int num)
{
if(L<=l&&r<=R) return d[num];
int mid=(l+r)>>;
if(L<=mid&&mid<R)
{
P1 x;
merge(x,getx(L,R,l,mid,lc),getx(L,R,mid+,r,rc));
return x;
}
else if(L<=mid)
return getx(L,R,l,mid,lc);
else if(mid<R)
return getx(L,R,mid+,r,rc);
else
exit(-);
}
}
void dfs1(int u,int fa)
{
sz[u]=;
for(int v,k=f1[u];k;k=e[k].nxt)
if(e[k].to!=fa)
{
v=e[k].to;
ff[v]=u;
dfs1(v,u);
sz[u]+=sz[v];
if(sz[v]>sz[hson[u]]) hson[u]=v;
}
}
P2 d1[];//d1[i]维护i节点及其轻儿子的贡献
P2 d2[];//d2[i]维护i节点(是重链顶)所在重链的值
int tp[],dwn[];//链顶,链底
inline void updd1(int x)
{
initnode(S::x,d1[x]);S::L=pl[x];S::_setx(,n,);
}
void dfs2(int u,int fa)
{
d1[u].a=a[u];
b[++b[]]=u;pl[u]=b[];
tp[u]=(u==hson[fa])?tp[fa]:u;
if(hson[u]) dfs2(hson[u],u);
dwn[u]=hson[u]?dwn[hson[u]]:u;
int v,k;
for(k=f1[u];k;k=e[k].nxt)
if(e[k].to!=fa&&e[k].to!=hson[u])
{
v=e[k].to;
dfs2(v,u);
d1[u].b+=d2[v].b;
d1[u].a+=d2[v].a;
}
updd1(u);
if(u==tp[u])
{
P1 t=S::getx(pl[u],pl[dwn[u]],,n,);
d2[u].a=t.a;d2[u].b=t.d+t.c;
}
}
inline ll getsize(int x)
{
return S::getx(pl[x],pl[dwn[x]],,n,).a;
}
int main()
{
int i,x,y,idx;ll z,ans,szall;P1 t;
scanf("%d%d",&n,&m);
for(i=;i<n;++i)
{
scanf("%d%d",&x,&y);
e[++ne].to=y;e[ne].nxt=f1[x];f1[x]=ne;
e[++ne].to=x;e[ne].nxt=f1[y];f1[y]=ne;
}
for(i=;i<=n;++i) scanf("%lld",a+i);
dfs1(,);
dfs2(,);
while(m--)
{
scanf("%d",&idx);
if(idx==)
{
scanf("%d%lld",&x,&z);
d1[x].a-=a[x];a[x]=z;d1[x].a+=z;
while(x)
{
updd1(x);
x=tp[x];y=ff[x];
t=S::getx(pl[x],pl[dwn[x]],,n,);
d1[y].a-=d2[x].a;d1[y].b-=d2[x].b;
d2[x].a=t.a;d2[x].b=t.d+t.c;
d1[y].a+=d2[x].a;d1[y].b+=d2[x].b;
x=y;
}
//printf("3t%d\n",d2[1].b);
}
else
{
scanf("%d",&x);
ans=d2[].b;
szall=getsize();
if(x!=tp[x])
{
y=tp[x];
z=d1[y].a;
d1[y].a+=szall-getsize(y);
updd1(y);
if(y!=dwn[y])
{
t=S::getx(pl[y]+,pl[dwn[y]],,n,);
ans-=t.c;
}
if(x!=dwn[y])
{
t=S::getx(pl[x]+,pl[dwn[y]],,n,);
ans+=t.c;
}
t=S::getx(pl[y],pl[x]-,,n,);
ans+=t.f;
d1[y].a=z;
updd1(y);
x=y;
}
while(x!=)
{
y=ff[x];
z=getsize(x);
ans-=z*z;
z=szall-z;
ans+=z*z;
x=y;
if(x!=tp[x])
{
y=tp[x];
z=d1[y].a;
d1[y].a+=szall-getsize(y);
updd1(y);
if(y!=dwn[y])
{
t=S::getx(pl[y]+,pl[dwn[y]],,n,);
ans-=t.c;
}
if(x!=dwn[y])
{
t=S::getx(pl[x]+,pl[dwn[y]],,n,);
ans+=t.c;
}
t=S::getx(pl[y],pl[x]-,,n,);
ans+=t.f;
d1[y].a=z;
updd1(y);
x=y;
}
}
printf("%lld\n",ans);
}
}
return ;
}
码完一看题解,???好像画风不太对??
所以还是无视上面那个代码吧...
正常得多的做法:
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
struct E
{
int to,nxt;
}e[];
int f1[],ne;
int n,m;
struct S
{
#define lowbit(x) ((x)&(-x))
ll d1[],d2[];
void _add(int p,ll x,ll *d)
{
for(;p<=n;p+=lowbit(p))
d[p]+=x;
}
ll _sum(int p,ll *d)
{
ll ans=;
for(;p>;p-=lowbit(p))
ans+=d[p];
return ans;
}
void add(int l,int r,ll x)
{
_add(l,x,d1);
_add(r+,-x,d1);
_add(l,x*l,d2);
_add(r+,-x*(r+),d2);
}
ll sum(int l,int r)
{
return (r+)*_sum(r,d1)-_sum(r,d2)
-l*_sum(l-,d1)+_sum(l-,d2);
}
}s1;
int b[],pl[];
ll a[],a2[];
int sz[],hson[],tp[];
ll dep[];
int ff[];
void dfs1(int u,int fa)
{
sz[u]=;
for(int k=f1[u];k;k=e[k].nxt)
if(e[k].to!=fa)
{
ff[e[k].to]=u;
dep[e[k].to]=dep[u]+;
dfs1(e[k].to,u);
sz[u]+=sz[e[k].to];
if(sz[e[k].to]>sz[hson[u]]) hson[u]=e[k].to;
}
}
void dfs2(int u,int fa)
{
b[++b[]]=u;pl[u]=b[];
tp[u]=u==hson[fa]?tp[fa]:u;
a2[u]=a[u];
if(hson[u])
{
dfs2(hson[u],u);
a2[u]+=a2[hson[u]];
}
for(int k=f1[u];k;k=e[k].nxt)
if(e[k].to!=fa&&e[k].to!=hson[u])
{
dfs2(e[k].to,u);
a2[u]+=a2[e[k].to];
}
}
inline ll gsum1(int x)//x到1的路径和
{
int y;ll an=;
for(;x;x=ff[y])
{
y=tp[x];
an+=s1.sum(pl[y],pl[x]);
}
return an;
}
inline void add1(int x,ll z)//x到1加上z
{
int y;
for(;x;x=ff[y])
{
y=tp[x];
s1.add(pl[y],pl[x],z);
}
}
ll anss;
int main()
{
ll ans,z,t;
int i,x,y,idx;
scanf("%d%d",&n,&m);
for(i=;i<n;++i)
{
scanf("%d%d",&x,&y);
e[++ne].to=y;e[ne].nxt=f1[x];f1[x]=ne;
e[++ne].to=x;e[ne].nxt=f1[y];f1[y]=ne;
}
for(i=;i<=n;++i)
scanf("%lld",a+i);
dfs1(,);
dfs2(,);
for(i=;i<=n;++i)
{
s1.add(pl[i],pl[i],a2[i]);
anss+=a2[i]*a2[i];
}
while(m--)
{
scanf("%d",&idx);
if(idx==)
{
scanf("%d%lld",&x,&z);
z=z-a[x];a[x]+=z;
anss+=z*z*(dep[x]+);
anss+=*gsum1(x)*z;
add1(x,z);
}
else
{
scanf("%d",&x);
ans=anss;
t=gsum1();
ans+=dep[x]*t*t;
ans-=*t*(gsum1(x)-t);
printf("%lld\n",ans);
}
}
return ;
}
洛谷 P3676 小清新数据结构题的更多相关文章
- 洛谷P3676 小清新数据结构题 【树剖 + BIT】
题目链接 洛谷P3676 题解 我们先维护\(1\)为根的答案,再考虑换根 一开始的答案可以\(O(n)\)计算出来 考虑修改,记\(s[u]\)表示\(u\)为根的子树的权值和 当\(u\)节点产生 ...
- 洛谷 P3676 - 小清新数据结构题(动态点分治)
洛谷题面传送门 题目名称好评(实在是太清新了呢) 首先考虑探究这个"换根操作"有什么性质.我们考虑在换根前后虽然每个点的子树会变,但整棵树的形态不会边,换句话说,割掉每条边后,得到 ...
- 洛谷P3676 小清新数据结构题(动态点分治+树链剖分)
传送门 感觉这题做下来心态有点崩……$RMQ$求$LCA$没有树剖快我可以理解为是常数太大……然而我明明用了自以为不会退化的点分然而为什么比会退化的点分跑得反而更慢啊啊啊啊~~~ 先膜一波zsy大佬 ...
- 洛谷P3676 小清新数据结构题 [动态点分治]
传送门 思路 这思路好妙啊! 首先很多人都会想到推式子之后树链剖分+线段树,但这样不够优美,不喜欢. 脑洞大开想到这样一个式子: \[ \sum_{x} sum_x(All-sum_x) \] 其中\ ...
- 【刷题】洛谷 P3676 小清新数据结构题
题目背景 本题时限2s,内存限制256M 题目描述 在很久很久以前,有一棵n个点的树,每个点有一个点权. 现在有q次操作,每次操作是修改一个点的点权或指定一个点,询问以这个点为根时每棵子树点权和的平方 ...
- 洛谷 P3672 小清新签到题 [DP 排列]
传送门 题意:给定自然数n.k.x,你要求出第k小的长度为n的逆序对对数为x的1~n的排列 $n \le 300, k \le 10^13$ 一下子想到hzc讲过的DP 从小到大插入,后插入不会对前插 ...
- [P3676]小清新数据结构题
Description: 给你一棵树,每次询问以一个点为根时所有子树点权和的平方和 带修改 Hint: \(n\le 2*10^5\) Solution: 这题只要推出式子就很简单了 如果不换根这个平 ...
- [洛谷P3672]小清新签到题
题目描述 题目还是简单一点好. 给定自然数n.k.x,你要求出第k小的长度为n的逆序对对数为x的1~n的排列a1,a2...an,然后用仙人图上在线分支定界启发式带花树上下界最小费用流解决问题,保证存 ...
- 并不对劲的p3676:小清新数据结构题
题目大意 有一棵有\(n\)(\(n\leq 2*10^5\))个点的树,要进行\(q\)(\(q\leq 2*10^5\))次操作,每次操作是以下两种中的一种: 1.修改一个点的点权 2.指定一个点 ...
随机推荐
- Android 7.1 GUI系统-窗口管理WMS-Surface管理(四)
Surface的管理 Surface是窗口能真正显示到物理屏幕上的基础,由surfaceflinger管理,可以通过WindowStateAnimator.java中的变量mDrawState来查看每 ...
- PHP的引用详解【转】
摘自:http://www.cnblogs.com/xiaochaohuashengmi/archive/2011/09/10/2173092.html 官方文档: 1.引用是什么:http://ww ...
- 搭建LoadRunner中的场景(三)场景的执行计划
所谓场景操作,包括初始化用户组.启动用户组各用户以及停止虚拟用户的全过程.依据设置不同,执行过程中可以最多有5类操作,分别是启动用户组(start group).初始化(Initialize).启动虚 ...
- codeforces 558C C. Amr and Chemistry(bfs)
题目链接: C. Amr and Chemistry time limit per test 1 second memory limit per test 256 megabytes input st ...
- pod lib lint 报错 Unable to find a specification for `AMap2DMap` depended upon by `DingtalkPod
执行 pod验证 报错如下 ➜ DingtalkPod git:(2.0.0) ✗ pod lib lint --sources='https://github.com/AloneMonkey/Mo ...
- phpstorm 2016.3.2 的最新破解方法(截止2017-2-20)
最新更新 ,http://idea.imsxm.com 这个地址是亲测可用的,针对最新的phpstorm 2016.3.2的版本.使用方式和下面一致,选择license server.然后复制http ...
- P2762 [网络流24题]太空飞行计划问题(最小割)
地址 最大权闭合子图裸题,不说了吧,求方案就是把s集遍历一遍. 错误记录:dfs那块忘判断残量了,11分×1. #include<cstdio> #include<iostream& ...
- 「UVA1636」Headshot(概率
题意翻译 你有一把枪(左轮的),你随机装了一些子弹,你开了一枪,发现没有子弹,你希望下一枪也没有子弹,你是应该直接开一枪(输出"SHOOT"),还是先转一下,再开一枪(输出&quo ...
- BZOJ 1567: [JSOI2008]Blue Mary的战役地图
1567: [JSOI2008]Blue Mary的战役地图 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 1011 Solved: 578[Sub ...
- transition插件
$("#box").transition({ opacity: 0.1, scale: 0.3 }); $("#box").transition({ opaci ...