BZOJ4719 NOIP2016天天爱跑步(线段树合并)

  线段树合并的话这个noip最难题就是个裸题了。

  注意merge最后return x,以及如果需要区间查询的话这里还需要up,无数次死于这里。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
#define N 300010
int n,m,p[N],a[N],fa[N][20],deep[N],ans[N],root[2][N],cnt[2]={0},t=0;
vector<int> op1[N],op2[N];
struct data{int to,nxt;
}edge[N<<1];
struct data2{int l,r,x;
}tree[2][N<<5];
void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
void dfs(int k)
{
    for (int i=p[k];i;i=edge[i].nxt)
    if (edge[i].to!=fa[k][0])
    {
        fa[edge[i].to][0]=k;
        deep[edge[i].to]=deep[k]+1;
        dfs(edge[i].to);
    }
}
int lca(int x,int y)
{
    if (deep[x]<deep[y]) swap(x,y);
    for (int j=19;~j;j--) if (deep[fa[x][j]]>=deep[y]) x=fa[x][j];
    if (x==y) return x;
    for (int j=19;~j;j--) if (fa[x][j]!=fa[y][j]) x=fa[x][j],y=fa[y][j];
    return fa[x][0];
}
int merge(int x,int y,int l,int r,int p)
{
    if (!x||!y) return x|y;
    if (l==r) {tree[p][x].x+=tree[p][y].x;return x;}
    int mid=l+r>>1;
    tree[p][x].l=merge(tree[p][x].l,tree[p][y].l,l,mid,p);
    tree[p][x].r=merge(tree[p][x].r,tree[p][y].r,mid+1,r,p);
    return x;
}
void ins(int &k,int x,int l,int r,int v,int p)
{
    if (!k) k=++cnt[p];
    if (l==r) {tree[p][k].x+=v;return;}
    int mid=l+r>>1;
    if (x<=mid) ins(tree[p][k].l,x,l,mid,v,p);
    else ins(tree[p][k].r,x,mid+1,r,v,p);
}
int query(int k,int l,int r,int x,int p)
{
    if (!k) return 0;
    if (l==r) return tree[p][k].x;
    int mid=l+r>>1;
    if (x<=mid) return query(tree[p][k].l,l,mid,x,p);
    else return query(tree[p][k].r,mid+1,r,x,p);
}
void getans(int k)
{
    for (int i=p[k];i;i=edge[i].nxt)
    if (edge[i].to!=fa[k][0])
    {
        getans(edge[i].to);
        root[0][k]=merge(root[0][k],root[0][edge[i].to],0,n<<1,0);
        root[1][k]=merge(root[1][k],root[1][edge[i].to],0,n<<1,1);
    }
    for (int i=0;i<op1[k].size();i++)
    if (op1[k][i]>0) ins(root[0][k],op1[k][i],0,n<<1,1,0);
    else ins(root[0][k],-op1[k][i],0,n<<1,-1,0);
    for (int i=0;i<op2[k].size();i++)
    if (op2[k][i]>0) ins(root[1][k],op2[k][i],0,n<<1,1,1);
    else ins(root[1][k],-op2[k][i],0,n<<1,-1,1);
    ans[k]+=query(root[0][k],0,n<<1,deep[k]+a[k],0)+query(root[1][k],0,n<<1,deep[k]-a[k]+n,1);
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("bzoj4719.in","r",stdin);
    freopen("bzoj4719.out","w",stdout);
#endif
    n=read(),m=read();
    for (int i=1;i<n;i++)
    {
        int x=read(),y=read();
        addedge(x,y),addedge(y,x);
    }
    fa[1][0]=1;dfs(1);
    for (int j=1;j<20;j++)
        for (int i=1;i<=n;i++)
        fa[i][j]=fa[fa[i][j-1]][j-1];
    for (int i=1;i<=n;i++) a[i]=read();
    for (int i=1;i<=m;i++)
    {
        int x=read(),y=read(),l=lca(x,y);
        if (l!=x) op1[x].push_back(deep[x]),op1[l==1?0:fa[l][0]].push_back(-deep[x]);
        if (l!=y) op2[y].push_back(deep[l]*2-deep[x]+n),op2[l==x?(l==1?0:fa[l][0]):l].push_back(deep[x]-deep[l]*2-n);
        if (l==x&&l==y&&a[l]==0) ans[l]++;
    }
    getans(1);
    for (int i=1;i<=n;i++) printf("%d ",ans[i]);
    return 0;
}

 

posted @ 2018-10-10 20:36  Gloid  阅读(156)  评论(0编辑  收藏  举报