ACM-ICPC 2018 焦作赛区网络预赛 E. Jiu Yuan Wants to Eat ,树链抛分+线段树
题目链接: E. Jiu Yuan Wants to Eat
题意:给一颗树,四种操作,第一种把u到v最短路上的点都乘上x,第二种把u到v最短路上的点都加上x,第三种把u到v最短路上的点都取反,第四种求u到v最短路上的点的和。
题解:标准的树抛然后用线段树维护,前两种都是线段树标准的修改操作,就是第三种不好搞得转换一下,~x=2^64-1-x;就可以取反转换成先乘-1在减1,然后就好做了。
#include<bits/stdc++.h> #define ll long long #define ull unsigned long long #define ls l,m,rt<<1 #define rs m+1,r,rt<<1|1 using namespace std; const int mod=1e9+7; int n; const int N = 1e5+100; int dep[N],fa[N],top[N],tid[N],son[N],siz[N],cn; int to[N*2],head[N*2],nxt[N*2]; int cnt; struct edge { int u,v,w; }e[N]; void add_edge(int u,int v) { to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt; } //树链抛分部分 void dfs1(int u,int f,int d)//第一次dfs用来找重儿子,深度,子树大小,父亲, { fa[u]=f;dep[u]=d;siz[u]=1; for(int i=head[u];i;i=nxt[i]) { if(to[i]!=f) { dfs1(to[i],u,d+1);siz[u]+=siz[to[i]]; if(son[u]==-1||siz[to[i]]>siz[son[u]])son[u]=to[i]; } } } void dfs2(int v,int tp)//得到重链的头节点,以及时间戳 { top[v]=tp; tid[v]=++cn; if(son[v]==-1)return; dfs2(son[v],tp); for(int i=head[v];i;i=nxt[i]) { if(to[i]!=fa[v]&&to[i]!=son[v]) { dfs2(to[i],to[i]); } } } ull mul[N<<2],ad[N<<2],sum[N<<2]; void init() { cnt=0;cn=0; memset(head,0,sizeof(head)); memset(son,-1,sizeof(son)); } void build(int l,int r,int rt){ mul[rt] = 1; ad[rt] = 0; sum[rt] = 0; if(l == r) return ; int mid = l+r>>1; build(l,mid,rt<<1); build(mid+1,r,rt<<1|1); } void push_down(int rt,int l,int r) { if(mul[rt]!=1) { sum[rt<<1]*=mul[rt]; ad[rt<<1]*=mul[rt]; mul[rt<<1]*=mul[rt]; sum[rt<<1|1]*=mul[rt]; ad[rt<<1|1]*=mul[rt]; mul[rt<<1|1]*=mul[rt]; mul[rt]=1; } if(ad[rt]) { int m=l+r>>1; sum[rt<<1]+=ad[rt]*(m-l+1); ad[rt<<1]+=ad[rt]; sum[rt<<1|1]+=ad[rt]*(r-m); ad[rt<<1|1]+=ad[rt]; ad[rt]=0; } } void push_up(int rt) { sum[rt]=sum[rt<<1]+sum[rt<<1|1]; } void update1(int L,int R,ull val,int l,int r,int rt) { if(L<=l&&r<=R) { sum[rt]*=val; ad[rt]*=val; mul[rt]*=val; return ; } push_down(rt,l,r); int m=l+r>>1; if(L<=m)update1(L,R,val,ls); if(R>m)update1(L,R,val,rs); push_up(rt); } void update2(int L,int R,ull val,int l,int r,int rt) { if(L<=l&&r<=R) { sum[rt]+=val*(r-l+1); ad[rt]+=val; return ; } push_down(rt,l,r); int m=l+r>>1; if(L<=m)update2(L,R,val,ls); if(R>m)update2(L,R,val,rs); push_up(rt); } ull query(int L,int R,int l,int r,int rt) { if(L<=l&&r<=R) { return sum[rt]; } push_down(rt,l,r); int m=l+r>>1; ull ans=0; if(L<=m)ans+=query(L,R,ls); if(R>m)ans+=query(L,R,rs); return ans; } void _mul(int x,int y,ull v) { int fx=top[x],fy=top[y]; while(top[fx]!=top[fy]) { if(dep[fx]>dep[fy]) update1(tid[fx],tid[x],v,1,n,1),x=fa[fx]; else update1(tid[fy],tid[y],v,1,n,1),y=fa[fy]; fx=top[x];fy=top[y]; } if(dep[x]<dep[y])swap(x,y); update1(tid[y],tid[x],v,1,n,1); } void _add(int x,int y,ull v) { int fx=top[x],fy=top[y]; while(top[fx]!=top[fy]) { if(dep[fx]>dep[fy]) update2(tid[fx],tid[x],v,1,n,1),x=fa[fx]; else update2(tid[fy],tid[y],v,1,n,1),y=fa[fy]; fx=top[x];fy=top[y]; } if(dep[x]<dep[y])swap(x,y); update2(tid[y],tid[x],v,1,n,1); } ull query_sum(int x,int y) { ull ans=0; int fx=top[x],fy=top[y]; while(top[fx]!=top[fy]) { if(dep[fx]>dep[fy]) ans+=query(tid[fx],tid[x],1,n,1),x=fa[fx]; else ans+=query(tid[fy],tid[y],1,n,1),y=fa[fy]; fx=top[x];fy=top[y]; } if(dep[x]<dep[y])swap(x,y); ans+=query(tid[y],tid[x],1,n,1); return ans; } int main() { while(scanf("%d",&n)==1) { init(); for(int i=2;i<=n;i++) { int x; scanf("%d",&x); add_edge(x,i); add_edge(i,x); } dfs1(1,0,0); dfs2(1,1); build(1,n,1); int m; scanf("%d",&m); for(int i = 1;i <= m;i ++){ int op,x,y; ull z; scanf("%d %d %d",&op,&x,&y); if(op == 1){ scanf("%llu",&z); _mul(x,y,z); } else if(op == 2){ scanf("%llu",&z); _add(x,y,z); } else if(op == 3){ _mul(x,y,-1); _add(x,y,-1); } else{ printf("%llu\n",query_sum(x,y)); } } } }