BZOJ 4719: [Noip2016] love every day running segment tree merger

title

BZOJ 4719

LUOGU 1600

Simplify the meaning of the questions:

小cStudents think that running is very interesting and decided to make a section called "Love every day running" of the game. "Love every day running" is to develop a game that requires players on the line every day on time to complete the task punch.

The game map can be considered as comprising eleven \ (n-\) nodes and \ (n-1 \) edges of the tree, each edge connects two nodes, and any two nodes there exists a path up to each other. The tree nodes numbered from \ (1 \) to the \ (n-\) consecutive positive integers.

Now there \ (m \) players, the \ (i \) players starting point for \ (S_i \) , end point \ (T_i \) . When the Punch daily task starts, all players in the first \ (0 \) while starting seconds from his starting point to an edge running speed per second, continuously toward their end ran along the shortest path to the finish line after even if that player completed the task punch. (Since the map is a tree, so everyone's path is unique)

小cWant to know the game activity, so each node have placed an observer. At node \ (J \) observers will choose the first \ (w_j \) seconds to observe the player, a player can observe the observer if and only if the first player \ (w_j \) s also taking processing reaches point \ (J \) . C wants to know every little observers will observe how many people?

Note: We believe that the players will end the game after a player reaches his end, he could not wait for some time before being observed to the observer. That is, for the nodes \ (J \) player as an endpoint: If he first \ (w_j \) reach the end seconds ago, then the node \ (J \) observer can not observe the player; if he just the first \ (w_j \) seconds to reach the end, at the junction point \ (J \) observers may observe the player.

analysis

For a man, his journey will be divided into two paragraphs, one up (root), the next stage, considering the contribution he can produce in the course of the viewer up what nature has: set the starting point depth \ (dep [x] \ ) , the observer depth \ (DEP [Y] \) , observed time is \ (T \) , must satisfy \ (DEP [X] -dep [Y] = T \) , in other words, \ (DEP [Y] + DEP T = [X] \) . Down that section similar derivation, the following section only in an upward path as an example to explain.

Now we recorded below each point starting point depth \ (dep [x] \) number, you need a starting point to the starting point and destination for each point of departure for updates \ (lca \) all points, expect to open a weight tree line, constantly upload the information to merge with the tree line, in \ (lca \) elimination of the impact of the update, so that we can direct statistical answer tree. Similar processing paths up-down path.

code

#include<bits/stdc++.h>

const int maxn=3e5+10;

namespace IO
{
    char buf[1<<15],*fs,*ft;
    inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
    template<typename T>inline void read(T &x)
    {
        x=0;
        T f=1, ch=getchar();
        while (!isdigit(ch) && ch^'-') ch=getchar();
        if (ch=='-') f=-1, ch=getchar();
        while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
        x*=f;
    }

    char Out[1<<24],*fe=Out;
    inline void flush() { fwrite(Out,1,fe-Out,stdout); fe=Out; }
    template<typename T>inline void write(T x,char str)
    {
        if (!x) *fe++=48;
        if (x<0) *fe++='-', x=-x;
        T num=0, ch[20];
        while (x) ch[++num]=x%10+48, x/=10;
        while (num) *fe++=ch[num--];
        *fe++=str;
    }
}

using IO::read;
using IO::write;

int ver[maxn<<1],Next[maxn<<1],head[maxn],len;
inline void add(int x,int y)
{
    ver[++len]=y,Next[len]=head[x],head[x]=len;
}

namespace SGT
{
    struct Orz{int l,r,z;}c[maxn*60];
    int num=0;
    inline void Change(int &x,int l,int r,int k,int z)
    {
        if (!x) x=++num;
        c[x].z+=z;
        if (l==r) return ;
        int mid=(l+r)>>1;
        if (k<=mid) Change(c[x].l,l,mid,k,z);
        else Change(c[x].r,mid+1,r,k,z);
    }

    inline int query(int x,int l,int r,int k)
    {
        if (l==r) return c[x].z;
        int mid=(l+r)>>1;
        if (k<=mid) return query(c[x].l,l,mid,k);
        else return query(c[x].r,mid+1,r,k);
    }

    inline int merge(int x,int y)
    {
        if (!x) return y;
        if (!y) return x;
        c[x].l=merge(c[x].l,c[y].l);
        c[x].r=merge(c[x].r,c[y].r);
        c[x].z=c[x].z+c[y].z;
        return x;
    }
}

using SGT::Change;
using SGT::query;
using SGT::merge;

namespace lca
{
    int dfn[maxn],id;
    int f[maxn][21],dep[maxn];
    inline void dfs(int x)
    {
        dfn[x]=++id;
        for (int i=1; i<=20; ++i) f[x][i]=f[f[x][i-1]][i-1];
        for (int i=head[x]; i; i=Next[i])
        {
            int y=ver[i];
            if (y==f[x][0]) continue;
            f[y][0]=x;
            dep[y]=dep[x]+1;
            dfs(y);
        }
    }

    inline int LCA(int x,int y)
    {
        if (dep[x]>dep[y]) std::swap(x,y);
        for (int i=20; i>=0; --i)
            if (dep[y]-(1<<i)>=dep[x]) y=f[y][i];
        if (x==y) return x;
        for (int i=20; i>=0; --i)
            if (f[x][i]^f[y][i]) x=f[x][i],y=f[y][i];
        return f[x][0];
    }
}

using lca::dfs;
using lca::LCA;
using lca::dep;
using lca::f;

int tot,n,m,u[maxn],v[maxn];
int ans[maxn],w[maxn];
inline void get(int x)
{
    for (int i=head[x]; i; i=Next[i])
    {
        int y=ver[i];
        if (y==f[x][0]) continue;
        get(y);
        u[x]=merge(u[x],u[y]), v[x]=merge(v[x],v[y]);
    }
    ans[x]=query(u[x],1,tot,dep[x]+w[x])+query(v[x],1,tot,w[x]-dep[x]+n);
}

int main()
{
    read(n);read(m); tot=n<<1;
    for (int i=1,x,y; i<n; ++i) read(x),read(y),add(x,y),add(y,x);
    for (int i=1; i<=n; ++i) read(w[i]);
    dfs(1);
    for (int i=1,x,y; i<=m; ++i)
    {
        read(x),read(y);
        int a=LCA(x,y);
        Change(u[x],1,tot,dep[x],1);
        Change(u[a],1,tot,dep[x],-1);
        Change(v[y],1,tot,dep[x]-(dep[a]<<1)+n,1);
        Change(v[f[a][0]],1,tot,dep[x]-(dep[a]<<1)+n,-1);
    }
    get(1);
    for (int i=1; i<=n; ++i) write(ans[i],' '); *IO::fe--;//防 BZOJ
    IO::flush();
    return 0;
}

Guess you like

Origin www.cnblogs.com/G-hsm/p/11426646.html