2017.6.27 树上操作 思考记录
2017-06-27 17:40
232 查看
这个题是以前应该做过、、
子树的话注意size就可以了,另外还要开longlong
另外标记是+-的,不是覆盖的、、
下传时要注意r-mid (开括号开错调了半天,数学太好了)
下传时应使用纯树上信息
码:
#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
#define zuo o<<1,l,mid
#define you o<<1|1,mid+1,r
#define N 100005
vector<int>v
;
long long ans,he[N<<2],i,sz
,d
,op,n,m,bj[N<<2],dui
,fu
,lzhi
,zhi
,top
,a,b,c,tot,hson
;
int x,y;
void dfs1(int now,int fa,int shen)
{
fu[now]=fa;
d[now]=shen;
sz[now]=1;
for(int i=0;i<v[now].size();i++)
{
int nd=v[now][i];
if(nd==fa)continue;
dfs1(nd,now,shen+1);
if(sz[nd]>sz[hson[now]])hson[now]=nd;
sz[now]+=sz[nd];
}
}
void dfs2(int now,int tap)
{
top[now]=tap;
dui[now]=++tot;
zhi[tot]=lzhi[now];
if(hson[now]!=0)dfs2(hson[now],tap);
for(int i=0;i<v[now].size();i++)
{
int nd=v[now][i];
if(nd==fu[now]||nd==hson[now])continue;
dfs2(nd,nd);
}
}
void up(int o)
{
he[o]=he[o<<1]+he[o<<1|1];
}
void jian(int o,int l,int r)
{
if(l==r)
{
he[o]=zhi[l];
return;
}
int mid=(l+r)>>1;
jian(zuo);
jian(you);
up(o);
}
void down(int o,int l,int r)
{
if(bj[o]!=0)
{
int mid=(l+r)>>1;
he[o<<1]+=bj[o]*(mid-l+1);
he[o<<1|1]+=bj[o]*(r-(mid+1)+1);
bj[o<<1]+=bj[o];
bj[o<<1|1]+=bj[o];
bj[o]=0;
}
}
void zhao(int o,int l,int r)
{
if(a<=l&&b>=r)
{
if(op==3)
ans+=he[o];
else {he[o]+=c*(r-l+1);bj[o]+=c;}
return;
}
down(o,l,r);
int mid=(l+r)>>1;
if(a<=mid)zhao(zuo);
if(b>mid)zhao(you);
up(o);
}
void workgai1(int x,int y)
{
a=dui[x];
b=dui[x];
c=y;
zhao(1,1,tot);
}
void workgai2(int x,int y)
{
a=dui[x];
b=dui[x]+sz[x]-1;
c=y;
zhao(1,1,tot);
}
void workzhao(int y)
{
ans=0;
x=1;
while(top[x]!=top[y])
{
if(d[top[x]]>d[top[y]])swap(x,y);
a=dui[top[y]];
b=dui[y];
zhao(1,1,tot);
y=fu[top[y]];
}
if(d[x]>d[y])swap(x,y);
a=dui[x];
b=dui[y];
zhao(1,1,tot);
}
int main()
{
scanf("%lld%lld",&n,&m);
for(i=1;i<=n;i++)scanf("%lld",&lzhi[i]);
for(i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
v[x].push_back(y);
v[y].push_back(x);
}
dfs1(1,1,1);
dfs2(1,1);
jian(1,1,n);
for(i=1;i<=m;i++)
{
scanf("%lld",&op);
if(op==1)
{
scanf("%d%d",&x,&y);
workgai1(x,y);
}
if(op==2)
{
scanf("%d%d",&x,&y);
workgai2(x,y);
}
if(op==3)
{
scanf("%d",&x);
workzhao(x);
printf("%lld\n",ans);
}
}
}
子树的话注意size就可以了,另外还要开longlong
另外标记是+-的,不是覆盖的、、
下传时要注意r-mid (开括号开错调了半天,数学太好了)
下传时应使用纯树上信息
码:
#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
#define zuo o<<1,l,mid
#define you o<<1|1,mid+1,r
#define N 100005
vector<int>v
;
long long ans,he[N<<2],i,sz
,d
,op,n,m,bj[N<<2],dui
,fu
,lzhi
,zhi
,top
,a,b,c,tot,hson
;
int x,y;
void dfs1(int now,int fa,int shen)
{
fu[now]=fa;
d[now]=shen;
sz[now]=1;
for(int i=0;i<v[now].size();i++)
{
int nd=v[now][i];
if(nd==fa)continue;
dfs1(nd,now,shen+1);
if(sz[nd]>sz[hson[now]])hson[now]=nd;
sz[now]+=sz[nd];
}
}
void dfs2(int now,int tap)
{
top[now]=tap;
dui[now]=++tot;
zhi[tot]=lzhi[now];
if(hson[now]!=0)dfs2(hson[now],tap);
for(int i=0;i<v[now].size();i++)
{
int nd=v[now][i];
if(nd==fu[now]||nd==hson[now])continue;
dfs2(nd,nd);
}
}
void up(int o)
{
he[o]=he[o<<1]+he[o<<1|1];
}
void jian(int o,int l,int r)
{
if(l==r)
{
he[o]=zhi[l];
return;
}
int mid=(l+r)>>1;
jian(zuo);
jian(you);
up(o);
}
void down(int o,int l,int r)
{
if(bj[o]!=0)
{
int mid=(l+r)>>1;
he[o<<1]+=bj[o]*(mid-l+1);
he[o<<1|1]+=bj[o]*(r-(mid+1)+1);
bj[o<<1]+=bj[o];
bj[o<<1|1]+=bj[o];
bj[o]=0;
}
}
void zhao(int o,int l,int r)
{
if(a<=l&&b>=r)
{
if(op==3)
ans+=he[o];
else {he[o]+=c*(r-l+1);bj[o]+=c;}
return;
}
down(o,l,r);
int mid=(l+r)>>1;
if(a<=mid)zhao(zuo);
if(b>mid)zhao(you);
up(o);
}
void workgai1(int x,int y)
{
a=dui[x];
b=dui[x];
c=y;
zhao(1,1,tot);
}
void workgai2(int x,int y)
{
a=dui[x];
b=dui[x]+sz[x]-1;
c=y;
zhao(1,1,tot);
}
void workzhao(int y)
{
ans=0;
x=1;
while(top[x]!=top[y])
{
if(d[top[x]]>d[top[y]])swap(x,y);
a=dui[top[y]];
b=dui[y];
zhao(1,1,tot);
y=fu[top[y]];
}
if(d[x]>d[y])swap(x,y);
a=dui[x];
b=dui[y];
zhao(1,1,tot);
}
int main()
{
scanf("%lld%lld",&n,&m);
for(i=1;i<=n;i++)scanf("%lld",&lzhi[i]);
for(i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
v[x].push_back(y);
v[y].push_back(x);
}
dfs1(1,1,1);
dfs2(1,1);
jian(1,1,n);
for(i=1;i<=m;i++)
{
scanf("%lld",&op);
if(op==1)
{
scanf("%d%d",&x,&y);
workgai1(x,y);
}
if(op==2)
{
scanf("%d%d",&x,&y);
workgai2(x,y);
}
if(op==3)
{
scanf("%d",&x);
workzhao(x);
printf("%lld\n",ans);
}
}
}
相关文章推荐
- 2017.7.18 树上距离=k 思考记录
- 2017.9.14 棘手的操作 思考记录
- 安卓跳转登录后如何记录之前的操作的问题思考
- 2017.9.10 序列操作 思考记录
- HDU 5956 树上进行斜率优化DP + 记录操作并撤销
- ASP.NET 2.0中用Gridview控件操作数据——使用Gridview插入新记录
- 数据库自动记录操作(事件探察器比较耗资源)
- 删除数据库中多个表中相关记录的操作
- 近期研究dotnet操作Excel,在这里作一个记录。
- 对单链(Single-Linked List)操作的思考
- 弹出窗口,回填记录的操作
- 有关hibernate操作修改的思考
- 2006-5-22 文本 转 HTML 与 HTML 转 文本 操作记录小结 By Stabx
- ACCESS数据库操作:重复记录仅显示其中一个,并显示多个字段
- 记录个人的思考过程
- 操作DataRow记录
- 利用P6SPY +SQL Profiler记录、统计web app对数据库的操作。
- 记录的添加,修改,删除等操作,??
- MASM-文件记录操作
- C#对XML操作:写入一笔XML记录(2)