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 小清新数据结构题的更多相关文章

  1. 洛谷P3676 小清新数据结构题 【树剖 + BIT】

    题目链接 洛谷P3676 题解 我们先维护\(1\)为根的答案,再考虑换根 一开始的答案可以\(O(n)\)计算出来 考虑修改,记\(s[u]\)表示\(u\)为根的子树的权值和 当\(u\)节点产生 ...

  2. 洛谷 P3676 - 小清新数据结构题(动态点分治)

    洛谷题面传送门 题目名称好评(实在是太清新了呢) 首先考虑探究这个"换根操作"有什么性质.我们考虑在换根前后虽然每个点的子树会变,但整棵树的形态不会边,换句话说,割掉每条边后,得到 ...

  3. 洛谷P3676 小清新数据结构题(动态点分治+树链剖分)

    传送门 感觉这题做下来心态有点崩……$RMQ$求$LCA$没有树剖快我可以理解为是常数太大……然而我明明用了自以为不会退化的点分然而为什么比会退化的点分跑得反而更慢啊啊啊啊~~~ 先膜一波zsy大佬 ...

  4. 洛谷P3676 小清新数据结构题 [动态点分治]

    传送门 思路 这思路好妙啊! 首先很多人都会想到推式子之后树链剖分+线段树,但这样不够优美,不喜欢. 脑洞大开想到这样一个式子: \[ \sum_{x} sum_x(All-sum_x) \] 其中\ ...

  5. 【刷题】洛谷 P3676 小清新数据结构题

    题目背景 本题时限2s,内存限制256M 题目描述 在很久很久以前,有一棵n个点的树,每个点有一个点权. 现在有q次操作,每次操作是修改一个点的点权或指定一个点,询问以这个点为根时每棵子树点权和的平方 ...

  6. 洛谷 P3672 小清新签到题 [DP 排列]

    传送门 题意:给定自然数n.k.x,你要求出第k小的长度为n的逆序对对数为x的1~n的排列 $n \le 300, k \le 10^13$ 一下子想到hzc讲过的DP 从小到大插入,后插入不会对前插 ...

  7. [P3676]小清新数据结构题

    Description: 给你一棵树,每次询问以一个点为根时所有子树点权和的平方和 带修改 Hint: \(n\le 2*10^5\) Solution: 这题只要推出式子就很简单了 如果不换根这个平 ...

  8. [洛谷P3672]小清新签到题

    题目描述 题目还是简单一点好. 给定自然数n.k.x,你要求出第k小的长度为n的逆序对对数为x的1~n的排列a1,a2...an,然后用仙人图上在线分支定界启发式带花树上下界最小费用流解决问题,保证存 ...

  9. 并不对劲的p3676:小清新数据结构题

    题目大意 有一棵有\(n\)(\(n\leq 2*10^5\))个点的树,要进行\(q\)(\(q\leq 2*10^5\))次操作,每次操作是以下两种中的一种: 1.修改一个点的点权 2.指定一个点 ...

随机推荐

  1. C#多线程编程介绍——使用thread、threadpool、timer

    C#多线程编程介绍——使用thread.threadpool.timer 在system.threading 命名空间提供一些使得能进行多线程编程的类和接口,其中线程的创建有以下三种方法:thread ...

  2. 机器学习 scikit-learn 图谱

    scikit-learn 是机器学习领域非常热门的一个开源库,基于Python 语言写成.可以免费使用. 网址: http://scikit-learn.org/stable/index.html 上 ...

  3. CF Round #460

    晚上去看月亮了 离比赛结束半个小时才滚回来A了T1T2T3... 又要掉Rating辣 T4 给一个有向图 每条边有一个英文字母作为边权 求一条路径 该路径上权值众数出现次数最多 求最多的出现次数 拓 ...

  4. 结合Mysql和kettle邮件发送日常报表_20161001

    十一假期 参加婚礼 稍晚点发博 整体流程步骤是: 写SQL-导出到excel设定excel模板调整格式-设置kettle转换--设置kettle邮件作业--完成 第一.写SQL 保持最近12个周的数据 ...

  5. Ubuntu Hadoop环境搭建(Hadoop2.6.5+jdk1.8.0_121)

    1.JDK的安装 2.配置hosts文件(这个也要拷贝给所有slave机,scp /etc/hosts root@slave1:/etc/hosts) gedit /etc/hosts 添加: 122 ...

  6. Python pip 报错

    1,pip ssl certification ssl: certificate_verify_failed... 2,Could not find a version that satisfies ...

  7. MemoryStream转string

    MemoryStream rtfTx = new MemoryStream(); var bs = rtfTx.ToArray(); string s = Encoding.UTF8.GetStrin ...

  8. WPF TabControl SelectionChanged 重复执行的问题

    很邪门的问题,我曾经都感觉是微软的bug了. 问题是这样的:在我的tabcontrol下的tabitem中有一个combobox控件,由于一些原因,需要执行tabcontrol的SelectionCh ...

  9. 读取web应用下的资源文件(例如properties)

    package gz.itcast.b_resource; import java.io.IOException; import java.io.InputStream; import java.ut ...

  10. Ext.Net 复制GridPanel的数据

    Ext.Net 复制GridPanel的数据 2013-11-28 09:50:04|  分类: Ext.net |  标签: |举报 |字号大中小 订阅     CSS: <styletype ...