大意:
就那么些操作,没有大意
思路:
这里就简单讲一下如何实现
首先,对于一条边,它有两个顶点,那么肯定是让深度较浅的点,也就是父节点的点权来作为这条边的边权。然后最后我们要查边权的时候,只要查它对应的子节点就可以了
那么我们为了实现该操作,在原本的板子上,有三点要进行改变:
1.dfs时更新点权,也就是让边权赋给子节点
- for(int i=head[id];i!=-1;i=edge[i].next)
- {
- ll y=edge[i].t;
- if(y==p) continue;
- a[y]=edge[i].l; //如果初始边权不为0,点权下放边权时要执行这一句操作
- init_dfs(y,id,depth+1);
- siz[id]+=siz[y];
- if(siz[y]>son_val)
- {
- son_val=siz[y];
- son[id]=y;
- }
- }
2.树上路径更新的时候,你稍微手玩一下就会发现两个节点的lca是不应该被更新的,所以在最后一步更新的时候,我们的代码要有所改变
- ll tree_add(ll x,ll y,ll val)
- {
- while(top[x]!=top[y])
- {
- if(dep[top[x]]
swap(x,y); - add(1,idx[top[x]],idx[x],val);
- x=fa[top[x]];
- }
- if(dep[x]>dep[y]) swap(x,y);
- add(1,idx[x]+1,idx[y],val);//lca不查询,所以x要+1
- }
当然你也可以这么写
- ll tree_add(ll x,ll y,ll val)
- {
- while(top[x]!=top[y])
- {
- if(dep[top[x]]
swap(x,y); - add(1,idx[top[x]],idx[x],val);
- x=fa[top[x]];
- }
- if(dep[x]>dep[y]) swap(x,y);
- add(1,idx[x],idx[y],val);
- add(1,idx[x],idx[x],-val);
- }
其实就是把lca的更新的结果给改回去
3.查询树上路径权值和时(如果有这个操作),同理两点的lca的点权不应该被算进去,因为它对应的边不属于这两点的路径上。
- ll tree_sum(ll x,ll y)
- {
- ll ans=0;
- while(top[x]!=top[y])
- {
- if(dep[top[x]]
swap(x,y); - ans+=sum(1,idx[top[x]],idx[x]);
- x=fa[top[x]];
- }
- if(dep[x]>dep[y]) swap(x,y);
- ans+=sum(1,idx[x]+1,idx[y]);//点权下放边权操作核心代码,lca不查询,所以x要+1
- return ans;
- }
同理,你也可以这么写,意思我就不解释了
- ll tree_sum(ll x,ll y)
- {
- ll ans=0;
- while(top[x]!=top[y])
- {
- if(dep[top[x]]
swap(x,y); - ans+=sum(1,idx[top[x]],idx[x]);
- x=fa[top[x]];
- }
- if(dep[x]>dep[y]) swap(x,y);
- ans+=sum(1,idx[x],idx[y]);
- ans-=sum(1,idx[x],idx[x]);
- return ans;
- }
会了这个操作之后这题你就毫无问题了
不过按惯例还是贴一下code
- #include
- using namespace std;
- #define ll int
- #define endl '\n'
- const ll N=1e5+10;
- struct ty{
- ll t,l,next;
- }edge[N<<1];
- ll cn=0;
- ll n,k;
- char op;
- ll aa,b,c,rt;
- ll head[N];
- void add_edge(ll a,ll b,ll c)
- {
- edge[++cn].t=b;
- edge[cn].l=c;
- edge[cn].next=head[a];
- head[a]=cn;
- }
- struct tree
- {
- ll l,r;
- ll val;
- ll add;//lazy
- ll siz;
- }tr[N<<2];
- ll dep[N];//深度
- ll fa[N],son[N];
- ll siz[N];
- ll mas[N],a[N];//初始序列,处理后的序列
- ll cnt=0;//dfs序的时间戳
- ll top[N];//所在链的顶端
- ll idx[N];
- void init_dfs(ll id,ll p,ll depth)
- {
- dep[id]=depth;
- fa[id]=p;
- siz[id]=1;
- ll son_val=0;
- for(int i=head[id];i!=-1;i=edge[i].next)
- {
- ll y=edge[i].t;
- if(y==p) continue;
- //a[y]=edge[i].l; 如果初始边权不为0,点权下放边权时要执行这一句操作
- init_dfs(y,id,depth+1);
- siz[id]+=siz[y];
- if(siz[y]>son_val)
- {
- son_val=siz[y];
- son[id]=y;
- }
- }
- }
- void dfs2(ll id,ll p)
- {//更新链上的情况
- idx[id]=++cnt;
- a[cnt]=mas[id];
- top[id]=p;
- if(!son[id]) return;
- dfs2(son[id],p);
- for(int i=head[id];i!=-1;i=edge[i].next)
- {
- ll y=edge[i].t;
- //if(y==p||y==son[id]) continue;
- if(!idx[y]) dfs2(y,y);//新的链
- }
- }
- void push_up(ll p)
- {
- tr[p].val+=tr[p<<1].val+tr[p<<1|1].val;
- }
- void build(ll p,ll l,ll r)
- {
- tr[p].l=l;tr[p].r=r;tr[p].siz=r-l+1;
- if(l==r)
- {
- tr[p].val=a[l];
- return;
- }
- ll mid=l+r>>1;
- build(p<<1,l,mid);
- build(p<<1|1,mid+1,r);
- }
- void push_down(ll p)
- {
- if(tr[p].add==0) return;
- tr[p<<1].val+=tr[p<<1].siz*tr[p].add;
- tr[p<<1|1].val+=tr[p<<1|1].siz*tr[p].add;
- tr[p<<1].add+=tr[p].add;
- tr[p<<1|1].add+=tr[p].add;
- tr[p].add=0;
- }
- void add(ll p,ll l,ll r,ll val)
- {
- if(tr[p].l>=l&&tr[p].r<=r)
- {
- tr[p].val+=tr[p].siz*val;
- tr[p].add+=val;
- return;
- }
- push_down(p);
- ll mid=tr[p].l+tr[p].r>>1;
- if(l<=mid) add(p<<1,l,r,val);
- if(r>mid) add(p<<1|1,l,r,val);
- push_up(p);
- }
- ll sum(ll p,ll l,ll r)
- {
- ll ans=0;
- if(tr[p].l>=l&&tr[p].r<=r)
- {
- return tr[p].val;
- }
- push_down(p);
- ll mid=tr[p].l+tr[p].r>>1;
- if(l<=mid) ans+=sum(p<<1,l,r);
- if(r>mid) ans+=sum(p<<1|1,l,r);
- return ans;
- }
- ll tree_sum(ll x,ll y)
- {
- ll ans=0;
- while(top[x]!=top[y])
- {
- if(dep[top[x]]
swap(x,y); - ans+=sum(1,idx[top[x]],idx[x]);
- x=fa[top[x]];
- }
- if(dep[x]>dep[y]) swap(x,y);
- ans+=sum(1,idx[x]+1,idx[y]);//点权下放边权操作核心代码,lca不查询,所以y要+1
- return ans;
- }
- ll tree_add(ll x,ll y,ll val)
- {
- while(top[x]!=top[y])
- {
- if(dep[top[x]]
swap(x,y); - add(1,idx[top[x]],idx[x],val);
- x=fa[top[x]];
- }
- if(dep[x]>dep[y]) swap(x,y);
- add(1,idx[x]+1,idx[y],val);//同上一句注释
- }
- void trson_add(ll x,ll val)
- {
- add(1,idx[x],idx[x]+siz[x]-1,val);
- }
- ll trson_sum(ll x)
- {
- return sum(1,idx[x],idx[x]+siz[x]-1);
- }
- void solve()
- {
- cin>>n>>k;
- for(int i=1;i
- {
- cin>>aa>>b;
- add_edge(aa,b,0);
- add_edge(b,aa,0);
- }
- init_dfs(rt,0,1);
- dfs2(rt,rt);
- build(1,1,n);
- while(k--)
- {
- cin>>op>>aa>>b;
- if(op=='P')
- {
- tree_add(aa,b,1);
- }
- else cout<<tree_sum(aa,b)<
- }
- }
- int main()
- {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
- memset(head,-1,sizeof head);
- rt=1;
- solve();
- return 0;
- }
-
相关阅读:
基于SpringBoot的服装生产管理系统的设计与实现
Coursera耶鲁大学金融课程:Financial Markets 笔记Week 02
Java 终极学习路线 - 共计 9 大模块 /6 大框架 /13 个中间件
【ATT&CK】ATT&CK视角下的水坑钓鱼攻防战法
图像文本跨模态细粒度语义对齐-置信度校正机制 AAAI2022
第83步 时间序列建模实战:Catboost回归建模
分布式消息队列RocketMQ概念详解
java之《浅入了解异常》适合预习,复习
java-php-net-python-基于ssh的酒店客房在线预定计算机毕业设计程序
第11章_数据处理之增删改
-
原文地址:https://blog.csdn.net/sophilex/article/details/126432341