bzoj 3631 [JLOI2014]松鼠的新家

来源:互联网 发布:java 开发就业班 编辑:程序博客网 时间:2024/04/19 17:05

题目

传送门

题解

看到某Yuta的树总结觉得LCA+树上差分挺好写而且差分没写过准备水一发结果水了一上午qwq。因为第一次写树上差分和树剖求LCA,结果树剖版子某处打错了。。(而且差分点和差分边还是有一定区别的)。


这题可以用树剖水部分分,不过n有30w,log方就会被卡了。所以利用差分思想把区间修改转化为点修改。给每个点一个tag表示新增值(貌似怪怪的)。如果有条路径(i,j)需要标记那么进行如下操作

tag(i)++;tag(j)++;tag(LCA(i,j))- -;tag(father(LCA(i,j)))- -;

这样能够达到标记经过的点的效果,请自行脑补如果是经过的边如何标记。
那么就把路径拆分就好了,但是这道题非起始端点会被多算一次(在衔接处),所以统计完后减回来。


题很水,人很蠢。

代码

//QWsin#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;const int maxn=600000+10;const int maxm=1200000+10;inline int read(){    int ret=0;char ch=getchar();    while(ch<'0'||ch>'9') ch=getchar();    for(;ch>='0'&&ch<='9';ch=getchar()) ret=ret*10+ch-'0';    return ret;}int to[maxn];int first[maxn],next[maxm],ecnt;struct Edge{int u,v;Edge(int u=0,int v=0):u(u),v(v){}}e[maxm];inline void add_edge(int u,int v){    next[ecnt]=first[u];first[u]=ecnt;e[ecnt++]=Edge(u,v);    next[ecnt]=first[v];first[v]=ecnt;e[ecnt++]=Edge(v,u);}int top[maxn],hv[maxn],sz[maxn],p[maxn],dep[maxn];int tag[maxn];  int dfs1(int u,int fa,int deep=1){    p[u]=fa;dep[u]=deep;sz[u]=1;int msz=0;    for(int i=first[u];i!=-1;i=next[i]) if(e[i].v!=fa){        int lch=dfs1(e[i].v,u,deep+1);        if(lch > msz) msz=lch,hv[u]=e[i].v;        sz[u]+=lch;    }    return sz[u];}void dfs2(int u,int Top){    top[u]=Top;    if(sz[u]==1) return ;    dfs2(hv[u],Top);    for(int i=first[u];i!=-1;i=next[i])        if(e[i].v!=p[u]&&e[i].v!=hv[u]) dfs2(e[i].v,e[i].v);}int LCA(int a,int b){    for(;top[a]!=top[b];b=p[top[b]])        if(dep[top[a]] > dep[top[b]]) swap(a,b);    return dep[a]<dep[b]?a:b;}int ans[maxn],sum,n;int dfs3(int cur){    int sum=tag[cur];    for(int i=first[cur];i!=-1;i=next[i])         if(e[i].v!=p[cur]) sum+=dfs3(e[i].v);    if(to[1]!=cur) ans[cur]=sum-1;    else ans[cur]=sum; return sum;}int main(){    n=read();memset(first,-1,sizeof(first));    for(int i=1;i<=n;i++) to[i]=read();    for(int i=1;i<n;i++) add_edge(read(),read());    int root=1;    dfs1(root,root);dfs2(root,root);    tag[to[1]]++;tag[to[2]]++;    int lca=LCA(to[1],to[2]);    tag[lca]--;if(lca!=root) tag[p[lca]]--;    for(int i=2;i<n;i++)    {        int lca=LCA(to[i],to[i+1]);        tag[to[i]]++;tag[to[i+1]]++;        tag[lca]--;if(lca!=root) tag[p[lca]]--;    }    dfs3(root);    for(int i=1;i<=n;i++) printf("%d\n",ans[i]);    return 0;}
2 0
原创粉丝点击