[BZOJ3631][JLOI2014]松鼠的新家

嗯。。。企图做ZJOI2011,结果一题都不会QAQ。生气的写树剖来了~

这题暴力的树剖是可以的,但我是在黄学长那找了这题,他好像有个非常妙的做法,现在差不多要去打ball了,之后再学习一下吧。

树剖:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<string>
#include<ctime>
#include<queue>
#include<map>
#include<set>
#include<vector>
typedef long long LL;
using namespace std;
const int N=300010;
struct edge{int to,nxt;}e[N<<1];
struct node{int l,r,lazy;}a[N<<2];
int n,b[N],head[N],cnt,pos[N],siz[N],bel[N],fa[N];
int read() {int d=0,f=1; char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();} while (c>='0'&&c<='9') d=(d<<3)+(d<<1)+c-48,c=getchar(); return d*f;}
void judge(){freopen(".in","r",stdin); freopen(".out","w",stdout);}
void addedge(int x,int y)
{
    e[++cnt]=(edge){y,head[x]}; head[x]=cnt;
    e[++cnt]=(edge){x,head[y]}; head[y]=cnt;
}
void dfs(int u)
{
    siz[u]=1;
    for (int i=head[u];i;i=e[i].nxt)
    {
        int v=e[i].to;
        if (v==fa[u]) continue;
        fa[v]=u; dfs(v); siz[u]+=siz[v];
    }
}
void dfs2(int u,int Bel)
{
    pos[u]=++cnt; bel[u]=Bel;
    int x=0;
    for (int i=head[u];i;i=e[i].nxt)
    {
        int v=e[i].to;
        if (v==fa[u]) continue;
        if (siz[v]>siz[x]) x=v;
    }
    if (!x) return;
    dfs2(x,Bel);
    for (int i=head[u];i;i=e[i].nxt)
    {
        int v=e[i].to;
        if (v==fa[u]||v==x) continue;
        dfs2(v,v);
    }
}
void pushdown(int k)
{
    if (!a[k].lazy) return;
    int k1=k<<1,k2=k1|1;
    a[k1].lazy+=a[k].lazy; a[k2].lazy+=a[k].lazy;
    a[k].lazy=0;
}
void build(int k,int l,int r)
{
    a[k]=(node){l,r,0};
    if (l==r) return;
    int mid=(l+r)>>1;
    build(k<<1,l,mid); build(k<<1|1,mid+1,r);
}
void update(int k,int l,int r,int v)
{
    if (l<=a[k].l&&a[k].r<=r) {a[k].lazy+=v; return;}
    pushdown(k);
    int mid=(a[k].l+a[k].r)>>1;
    if (r<=mid) update(k<<1,l,r,v);
    else if (l>mid) update(k<<1|1,l,r,v);
    else update(k<<1,l,mid,v),update(k<<1|1,mid+1,r,v);
}
int ask(int k,int x)
{
    if (a[k].l==a[k].r) return a[k].lazy;
    pushdown(k);
    int mid=(a[k].l+a[k].r)>>1;
    if (x<=mid) return ask(k<<1,x);
    else return ask(k<<1|1,x);
}
int main()
{
    //judge();
    n=read();
    for (int i=1;i<=n;i++) b[i]=read();
    for (int i=1;i<n;i++) addedge(read(),read());
    dfs(1); cnt=0; dfs2(1,1); build(1,1,n);
    int x=b[1];
    for (int i=2;i<=n;i++)
    {
        int y=b[i];
        while (bel[x]!=bel[y])
        {
            if (pos[x]<pos[y]) swap(x,y);
            update(1,pos[bel[x]],pos[x],1);
            x=fa[bel[x]];
        }
        if (pos[x]>pos[y]) swap(x,y);
        update(1,pos[x],pos[y],1);
        x=b[i];
        update(1,pos[x],pos[x],-1);
    }
    for (int i=1;i<=n;i++) printf("%d
",ask(1,pos[i]));
    return 0;
}
View Code

未完待续...

摘自黄学长:http://hzwer.com/4522.html

其实是可以直接上树链剖分的

但是我们发现这道题只要实现每次将u-v路径的点权+1

只要在u和v上打个+1标记,lca(u,v)和lca(u,v)->fa打-1标记,最后dp上传标记即可

本质是个差分。。。

代码就不写了~(≧▽≦)/~啦啦啦

完结~

原文地址:https://www.cnblogs.com/lujiaju6555/p/6789549.html