动态开点、线段树合并

P1908 逆序对
//
搞不明白哪里要差分? //桶用来装该深度的点对 对应的 点的贡献 #include<bits/stdc++.h> const int N=3e5+11; using namespace std; int n,m,cnt,head[N],w[N],fa[N]; int son[N],sz[N],dep[N],ans[N]; int num[N],top[N],bucket[N*3]; vector<int> v1[N],v2[N],v3[N]; struct Edge{int nxt,to;}edge[N<<1]; int read(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();} while(isdigit(ch)){x=x*10+ch-48;ch=getchar();} return x*f; } void ins(int x,int y){ edge[++cnt].nxt=head[x]; edge[cnt].to=y;head[x]=cnt; } void dfs1(int x,int fat){//父亲、深度、子树大小、重儿子 for(int i=head[x];i;i=edge[i].nxt){ int y=edge[i].to; if(y==fat) continue; fa[y]=x;dep[y]=dep[x]+1; dfs1(y,x);sz[x]+=sz[y]; if(sz[y]>sz[son[x]]) son[x]=y; }++sz[x]; } void dfs2(int x,int topx){//轻重链剖分 top[x]=topx; if(!son[x]) return ; dfs2(son[x],topx); for(int i=head[x];i;i=edge[i].nxt){ int y=edge[i].to; if(y==fa[x]||y==son[x]) continue; dfs2(y,y); } } int Lca(int x,int y){//求lca while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]]) swap(x,y); x=fa[top[x]]; }return dep[x]<dep[y]?x:y; } int dis(int x,int y){//两个点路径长度 return dep[x]+dep[y]-(dep[Lca(x,y)]<<1); } void calc1(int x){ int pre=bucket[dep[x]+w[x]+N]; for(int i=head[x];i;i=edge[i].nxt){ int y=edge[i].to; if(y==fa[x]) continue; calc1(y); } bucket[dep[x]+N]+=num[x]; ans[x]+=bucket[dep[x]+w[x]+N]-pre; for(int i=0;i<v1[x].size();i++)//离开以x为根的子树就没有意义了 --bucket[dep[v1[x][i]]+N]; } void calc2(int x){ int pre=bucket[w[x]-dep[x]+N]; for(int i=head[x];i;i=edge[i].nxt){ int y=edge[i].to; if(y==fa[x]) continue; calc2(y); } for(int i=0;i<v3[x].size();i++) ++bucket[dis(x,v3[x][i])-dep[x]+N]; ans[x]+=bucket[w[x]-dep[x]+N]-pre; for(int i=0;i<v2[x].size();i++) --bucket[v2[x][i]+N]; } signed main(){ n=read(),m=read(); for(int i=1;i<n;i++){ int x=read(),y=read(); ins(x,y),ins(y,x); } for(int i=1;i<=n;i++) w[i]=read(); dfs1(1,0);dfs2(1,1); for(int i=1;i<=m;i++){ int x=read(),y=read(); num[x]++; int lca=Lca(x,y); v1[lca].push_back(x); v2[lca].push_back(dis(x,y)-dep[y]); v3[y].push_back(x); if(dep[lca]+w[lca]==dep[x]) --ans[lca]; } calc1(1);calc2(1); for(int i=1;i<=n;i++) printf("%d ",ans[i]); return 0; }

猜你喜欢

转载自www.cnblogs.com/caterpillor/p/13203702.html
今日推荐