开店【题解】

7 篇文章 0 订阅
6 篇文章 0 订阅

前言

这道题居然调了我一晚上,原因如下:
1. 题解错误,所以对拍老是出错
2. 建边的数组太多了。有一个忘记*2

题面

sol

不知道大家有没有想用点分治写但又不会STL的vector。这里,只要使用一下指针就可以了。首先开一个N*150的空间,对于每一个点都开一个指针,最后根据每一个点的大小用指针动态分配一段空间就行了。
解法其实自然。动态点分治难点就在于建立own和tofa两个数组.但这道题难点却在卡空间.注意到要询问[L,R]的信息。最容易想到的是值域线段树等,但是空间很可能开不下。如果用值域树状数组,离散化后可能开的下。但注意到这道题不需要区间修改,只需要查询,这样的话,查询可以做到O(1),用一个前缀和就行了。等数组内元素装满后,直接按年龄sort,查询时用lower_bound,upper_bound找到位置,直接查询。

code

#include<bits/stdc++.h>
#define LL long long
using namespace std;
template <class T>
inline void read(T&data){
    data=0;
    register char ch=0;
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch<='9'&&ch>='0'){
        data=(data<<3)+(data<<1)+(ch&15);
        ch=getchar();
    }
    return;
}
template <class T>
inline void write(T data){
    if(data>9)write(data/10);
    putchar(data%10+'0');
}
const int _ =1.5e5+1,INF= 2e9+1;
int to[_<<1],nxt[_<<1],all,head[_],val[_<<1],cnt,size[_],par[_],root,MX,n,Q,A,age[_];
int st[_<<1][21],lg[_<<1],tot,dfn[_],rec[_],fdfn[_],vnt[_],rt;
struct node{
    int zh;LL dist;//zh是年龄
};
LL dis[_];
node mem[_*150],*own[_],*tofa[_],*PIN=mem;
bool vis[_];
inline void  add(register int a,register int b,register int c){to[++cnt]=a,nxt[cnt]=head[b],val[cnt]=c,head[b]=cnt;}
void dfsI(register int now,register int ff){
    dfn[now]=++cnt,fdfn[cnt]=now,st[++tot][0]=cnt,rec[now]=tot;
    for(register int i=head[now];i;i=nxt[i]){
        if(to[i]==ff)continue;
        dis[to[i]]=dis[now]+val[i];
        dfsI(to[i],now);
        st[++tot][0]=dfn[now];
    }return;
}
inline LL getdist(register int a,register int b){
    register int u=rec[a],v=rec[b];
    if(u>v)swap(u,v);
    register int Len=lg[v-u+1];
    return dis[a]+dis[b]-2*dis[fdfn[min(st[u][Len],st[v+1-(1<<Len)][Len] ) ] ];
}
void getroot(register int now,register int ff){
    size[now]=1;
    register int mx=0;
    for(register int i = head[ now ] ; i ; i = nxt[ i ]){
        if(vis[ to[ i ] ] || to[ i ] == ff)continue;
        getroot( to[ i ], now );
        size[ now ] += size[ to[ i ] ];
        mx=max( mx , size[ to[ i ] ]);
    }
    mx=max(mx,all-size[now]);
    if(MX>mx) MX = mx,root=  now;
    return;
}
void divide(register int now){
    vis[now]=1;
    for(register int i=head[now];i;i=nxt[i]){
        if(vis[to[i]])continue;
        MX=INF,all=size[to[i]];
        getroot(to[i],now);
        par[root]=now;//cout<<now<<' '<<root<<endl;
        own[root]=PIN,PIN+=all+1,tofa[root]=PIN,PIN+=all+1;
        divide(root);
    }return;
}
inline bool cmp(const node a,const node b){return a.zh<b.zh;}
inline void init(){
    for(register int i=1;i<=n;++i){
        if(i!=rt)sort(tofa[i]+1,tofa[i]+vnt[i]+1,cmp);
        sort(own[i]+1,own[i]+vnt[i]+1,cmp);
        for(register int j=2;j<=vnt[i];++j)own[i][j].dist=own[i][j-1].dist+own[i][j].dist;
        if(i!=rt)for(register int j=2;j<=vnt[i];++j)tofa[i][j].dist=tofa[i][j-1].dist+tofa[i][j].dist;
    }
}
inline void pre_build(register int x){
    own[x][++vnt[x]]=(node){age[x],0};
    for(register int i=x,dist;par[i];i=par[i]){
        dist = getdist(x,par[i]);
        own[par[i]][++vnt[par[i] ] ]=(node){age[x],dist};
        tofa[i][vnt[i] ]=(node){age[x],dist};
    }
    return;
}
inline LL query(register int le,register int ri,register int x){
    register LL ret=0;
    register int l=lower_bound(own[x]+1,own[x]+vnt[x]+1,(node){le,0},cmp)-own[x]-1;
    register int r=upper_bound(own[x]+1,own[x]+vnt[x]+1,(node){ri,0},cmp)-own[x]-1;
    ret+=own[x][r].dist-own[x][l].dist;
    register LL dist;
    //cout<<ret<<endl;
    for(register int i=x;par[i];i=par[i]){
        //cout<<i<<' '<<par[i]<<endl;
        dist = getdist(par[i],x);
        ret-=tofa[i][r].dist-tofa[i][l].dist+dist*(r-l);//cout<<ret<<endl;
        l=lower_bound(own[par[i]]+1,own[par[i]]+vnt[par[i]]+1,(node){le,0},cmp)-own[par[i]]-1;
        r=upper_bound(own[par[i]]+1,own[par[i]]+vnt[par[i]]+1,(node){ri,0},cmp)-own[par[i]]-1;
        ret+=own[par[i]][r].dist-own[par[i]][l].dist+dist*(r-l);
        //cout<<ret<<endl;
    }
    return ret;
}
int main(){
    freopen("data.in","r",stdin);
    freopen("1.out","w",stdout);
    read(n),read(Q),read(A);
    for(register int i=1;i<=n;++i)read(age[i]);
    for(register int i=1,a,b,c;i<n;++i)read(a),read(b),read(c),add(a,b,c),add(b,a,c);
    cnt=0;
    dfsI(1,0);
    for(register int i=2;i<=2*n;++i)lg[i]=lg[i>>1]+1;
    for(register int j=1;j<=20;++j)
        for(register int i=1;i+(1<<(j-1))<2*n;++i)
            st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
    MX=INF,all=n;
    getroot(1,0);
    own[root]=PIN,PIN+=n+1;rt=root;
    divide(root);
    for(register int i=1;i<=n;++i)
        pre_build(i);
    register LL ans=0;
    init();//exit(0);
    //Q=1;
    for(register int i=1;i<=Q;++i){
        register LL a,b;register int u;
        read(u),read(a),read(b);a+=ans,b+=ans;
        a%=A,b%=A;if(a>b)swap(a,b);
        ans=query(a,b,u);
        //printf("%lld\n",ans);
        write(ans);puts("");
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值