【HNOI2015】开店

来源:互联网 发布:js 字符串相等 编辑:程序博客网 时间:2024/03/28 18:08

Description

给出一棵二叉树,每个点有点权,多次询问所有点权在[l,r]范围内的点到x的距离和。
强制在线。
n<=1.5*1e5,q<=2*1e5,权值<=1e9

Solution

为什么年龄可以达到10^9呢?因为有紫asdfjawkejtwlkerj

这道题可以直接把虚树用线段树建出来,然后直接在虚树上乱搞,不过我很弱显然不会这种做法。
发现这棵树是二叉树耶,于是我们可以考虑一种又好写又能跑得过空间又小的做法:点分治!
考虑把点分树建出来,那么我就是需要对于每个点分树中的子树包含x的点统计它的子树中有多少条经过它到x的路径。
更一般一点我们需要求出某一个点的子树中除了某一个儿子的子树以外的点到x的距离和。
考虑我们求的是点分树,于是我们可以知道所有点的size之和为O(n log n)
所以我们可以暴力求出每一个点根它子树中的所有点,按年龄从小到大排序,查询这个点的时候直接二分即可。
发现这棵树是二叉树,所以我们只需要暴力开空间就够了,完全不虚。
不然可能还需要写一棵线段树emmmm

Code

#include <cmath>#include <cstdio>#include <cstring>#include <algorithm>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fd(i,a,b) for(int i=a;i>=b;i--)#define rep(i,a) for(int i=lst[a];i;i=nxt[i])using namespace std;typedef long long ll;int read() {    char ch;    for(ch=getchar();ch<'0'||ch>'9';ch=getchar());    int x=ch-'0';    for(ch=getchar();ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';    return x;}void write(ll x) {    if (!x) {puts("0");return;}    char ch[20];int tot=0;    for(;x;x/=10) ch[++tot]=x%10+'0';    fd(i,tot,1) putchar(ch[i]);    puts("");}const int N=1.5*1e5+5,M=4*1e5+5;int t[M],nxt[M],lst[N],v[M],num;void add(int x,int y,int z) {    t[++num]=y;v[num]=z;nxt[num]=lst[x];lst[x]=num;}int n,m,age[N],x,y,z,l,r,a,b,A;struct P{int x,z;}p[N<<5];bool cmp(P x,P y) {return age[x.x]<age[y.x];}int size[N],Sz,rt,fa[N],L[N][3],R[N][3],cnt[N],son[N][3],tot;bool bz[N];void get_size(int x,int y) {    size[x]=1;    rep(i,x) if (!bz[t[i]]&&t[i]!=y) get_size(t[i],x),size[x]+=size[t[i]];}void find_root(int x,int y) {    bool pd=1;    rep(i,x)         if (!bz[t[i]]&&t[i]!=y) {            find_root(t[i],x);            if (size[t[i]]>Sz/2) pd=0;        }    if (Sz-size[x]>Sz/2) pd=0;    if (pd) rt=x;}void dfs(int x,int y,int z) {    p[++tot].x=x;p[tot].z=z;    rep(i,x) if (!bz[t[i]]&&t[i]!=y) dfs(t[i],x,z+v[i]);}int solve(int x,int y) {    get_size(x,0);    Sz=size[x];find_root(x,0);    int now=rt;    rep(i,now)         if (!bz[t[i]]) {            L[now][cnt[now]]=tot+1;            dfs(t[i],now,v[i]);            R[now][cnt[now]++]=tot;        }    int ret=0;bz[now]=1;fa[now]=y;    rep(i,now) if (!bz[t[i]]) son[now][ret++]=solve(t[i],now);    return now;} int fir[N<<1],dfn[N<<1],dep[N],lg[N<<1],f[18][N<<1],sum[N],tmp;ll pre[N<<5];void travel(int x,int y) {    fir[x]=++tmp;dfn[tmp]=x;dep[x]=dep[y]+1;    rep(i,x) if (t[i]!=y) {sum[t[i]]=sum[x]+v[i];travel(t[i],x);dfn[++tmp]=x;}}int lca(int x,int y) {    x=fir[x];y=fir[y];    if (x>y) swap(x,y);    int z=lg[y-x+1];    if (dep[f[z][x]]<dep[f[z][y-(1<<z)+1]]) return f[z][x];    else return f[z][y-(1<<z)+1];}int dist(int x,int y) {    int z=lca(x,y);    return sum[x]+sum[y]-2*sum[z];}int find(int l,int r,int v) {    r++;    while (l<r) {        int mid=l+r>>1;        if (age[p[mid].x]<=v) l=mid+1;        else r=mid;    }    return l-1;}ll query(int x,int v) {    ll res=0;    for(int la=0,i=x;i;la=i,i=fa[i]) {        int D=dist(x,i);        res+=(age[i]<=v)*D;        fo(j,0,cnt[i]-1)             if (son[i][j]!=la) {                int pos=find(L[i][j],R[i][j],v);                res+=(ll)(pos-L[i][j]+1)*D;                res+=pre[pos]-pre[L[i][j]-1];            }    }    return res;}int main() {    freopen("shop.in","r",stdin);    freopen("shop.out","w",stdout);    n=read();m=read();A=read();    fo(i,1,n) age[i]=read();    fo(i,1,n-1) {        x=read();y=read();z=read();        add(x,y,z);add(y,x,z);    }    solve(1,0);    fo(i,1,n) fo(j,0,cnt[i]-1) sort(p+L[i][j],p+R[i][j]+1,cmp);    fo(i,1,tot) pre[i]=pre[i-1]+p[i].z;    travel(1,0);    fo(i,1,tmp) f[0][i]=dfn[i],lg[i]=log(i)/log(2);    fo(j,1,17)        fo(i,1,tmp-(1<<j))            if (dep[f[j-1][i]]<dep[f[j-1][i+(1<<j-1)]]) f[j][i]=f[j-1][i];            else f[j][i]=f[j-1][i+(1<<j-1)];    ll ans=0;    for(;m;m--) {        x=read();a=read();b=read();        l=min((a+ans)%A,(b+ans)%A);        r=max((a+ans)%A,(b+ans)%A);        write(ans=query(x,r)-query(x,l-1));    }    return 0;}
原创粉丝点击