HNOI2015 开店

题目链接在此
这道题其实有两种做法,动态点分治和树剖+主席树.
我怕麻烦,写了动态点分治.
结果还是写了\(100+\)行...


考虑这道题怎么做.
先离散化一下.
我们先建好点分树,然后用一个\(vector\)记录这个点在点分树上的子树节点的所有信息.
这个时空复杂度是\(O(n*log\ n)\)
然后我们按每个点的权值排序,每个节点\(vector\)上的点再记录\(3\)个信息:子树内所有点的权值排名,子树内所有的点到这个点的距离,子树内所有点到这个点父亲的距离.
求这个距离和直接暴力算就可以了.
但是要用\(O(1)\)\(lca\)

然后我们做一遍后缀和(为了方便\(upper\_bound\)\(lower\_bound\)).
如何查询呢?
就直接在点分树上暴力跳父亲.假设询问点是\(u\),现在的点是\(f\).那么,\(ans+=dis(u,f)*f\)中所有不包含\(u\)的子树\(size\)\(+f\)中所有不包含\(u\)的子树到\(f\)的距离
然而,这里所有的东西我们都预处理好了.
那么,只要拿两个指针二分出子树内点的权值,然后计算即可.
不要忘记加上\(f\)的贡献.

时间复杂度大约是\(O(n*log^2n*T)\)的,其中\(T\)指大常数.

我可能语文不太好,可以通过代码理解一下.
自认为还是比较通俗易懂的.

下面是又长常数又大的代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#define N (150010)
#define M (N<<1)
#define inf (0x7f7f7f7f)
#define rg register int
#define Label puts("NAIVE")
#define spa print(' ')
#define ent print('\n')
#define rand() (((rand())<<(15))^(rand()))
typedef long double ld;
typedef long long LL;
typedef unsigned long long ull;
using namespace std;
inline char read(){
	static const int IN_LEN=1000000;
	static char buf[IN_LEN],*s,*t;
	return (s==t?t=(s=buf)+fread(buf,1,IN_LEN,stdin),(s==t?-1:*s++):*s++);
}
template<class T>
inline void read(T &x){
	static bool iosig;
	static char c;
	for(iosig=false,c=read();!isdigit(c);c=read()){
		if(c=='-')iosig=true;
		if(c==-1)return;
	}
	for(x=0;isdigit(c);c=read())x=((x+(x<<2))<<1)+(c^'0');
	if(iosig)x=-x;
}
inline char readchar(){
	static char c;
	for(c=read();!isalpha(c);c=read())
	if(c==-1)return 0;
	return c;
}
const int OUT_LEN = 10000000;
char obuf[OUT_LEN],*ooh=obuf;
inline void print(char c) {
	if(ooh==obuf+OUT_LEN)fwrite(obuf,1,OUT_LEN,stdout),ooh=obuf;
	*ooh++=c;
}
template<class T>
inline void print(T x){
	static int buf[30],cnt;
	if(x==0)print('0');
	else{
		if(x<0)print('-'),x=-x;
		for(cnt=0;x;x/=10)buf[++cnt]=x%10+48;
		while(cnt)print((char)buf[cnt--]);
	}
}
inline void flush(){fwrite(obuf,1,ooh-obuf,stdout);}
struct node{
    int val,id,cnt; LL s,s1;
    friend bool operator <(node a,node b){
        return a.val<b.val;
    }
};
typedef vector<node>::iterator iter;
int n,m,A,ls[N],w[N],f[20][N<<2],dis[N],dfn[N<<2],rdfn[N<<2],ind;
int fi[N],ne[M],b[M],E,dep[N],c[M],AA;
int son[N],siz[N],R,root,sum,fa[N],sz[N],lg[N<<2];
vector<int> nxt[N];
vector<node> tr[N];
bool vis[N];
void add(int x,int y,int z){
    ne[++E]=fi[x],fi[x]=E,b[E]=y,c[E]=z;
}
void dfs(int u,int pre){
    rdfn[++ind]=u,dfn[u]=ind;
    for(int i=fi[u];i;i=ne[i]){
        int v=b[i];
        if(v==pre)continue;
        dep[v]=dep[u]+1,dis[v]=dis[u]+c[i],dfs(v,u);
        rdfn[++ind]=u;
    }
}
LL getdis(int x,int y){
    if(!x||!y)return 0;
    if(dfn[x]>dfn[y])swap(x,y);
    int k=lg[dfn[y]-dfn[x]+1],ans;
    if(dep[f[k][dfn[x]]]<dep[f[k][dfn[y]-(1<<k)+1]])
    ans=f[k][dfn[x]];
    else ans=f[k][dfn[y]-(1<<k)+1];
    return dis[x]+dis[y]-2*dis[ans];
}
void init(){
    dfs(1,0);
    for(int i=1;i<=ind;i++)f[0][i]=rdfn[i];
    for(int i=1;i<=ind;i++)lg[i]=lg[i>>1]+1;
    for(int i=1;i<=19;i++)
    for(int j=1;j+(1<<i)<=ind;j++){
    	if(dep[f[i-1][j]]<dep[f[i-1][j+(1<<(i-1))]])f[i][j]=f[i-1][j];
    	else f[i][j]=f[i-1][j+(1<<(i-1))];
	}
    
}
void find_root(int u,int pre){
    siz[u]=1,son[u]=0;
    for(int i=fi[u];i;i=ne[i]){
        int v=b[i];
        if(vis[v]||v==pre)continue;
        find_root(v,u);
        siz[u]+=siz[v];
        son[u]=max(siz[v],son[u]);
    }
    son[u]=max(son[u],sum-siz[u]);
    if(son[u]<son[root])root=u;
}
void solve(int u,int pre){
    fa[u]=pre,vis[u]=1,sz[u]=1;
    tr[u].push_back((node){w[u],u,0,getdis(u,pre),0});
    for(int i=fi[u];i;i=ne[i]){
        int v=b[i];
        if(vis[v])continue;
        root=0,sum=siz[v];
        find_root(v,0);
        nxt[u].push_back(root);
        int tmp=root;
        solve(root,u),sz[u]+=sz[tmp];
        for(int i=0;i<tr[tmp].size()-1;i++)
        tr[u].push_back((node){tr[tmp][i].val,tr[tmp][i].id,0,getdis(tr[tmp][i].id,pre),getdis(tr[tmp][i].id,u)});
    }
    tr[u].push_back((node){A+1,0,1,0,0});
    sort(tr[u].begin(),tr[u].end());
    for(int i=tr[u].size()-2;i>=0;i--)
    tr[u][i].s=tr[u][i+1].s+tr[u][i].s,
    tr[u][i].s1=tr[u][i+1].s1+tr[u][i].s1,
    tr[u][i].cnt=tr[u].size()-i;
}
LL query(int l,int r,int st){
    LL ans=0;
    for(int u=st,pre=0;u;pre=u,u=fa[u]){
        if(u==st){
            iter L=lower_bound(tr[u].begin(),tr[u].end(),(node){l,0,0,0,0});
            iter R=upper_bound(tr[u].begin(),tr[u].end(),(node){r,0,0,0,0});
            LL val=L->s1-R->s1;
            ans+=val;continue;
        }
        LL len=getdis(st,u);
        LL sums=0,sumd=0;
        for(int i=0;i<nxt[u].size();i++)
        if(nxt[u][i]!=pre){
            int v=nxt[u][i];
            iter L=lower_bound(tr[v].begin(),tr[v].end(),(node){l,0,0,0,0});
            iter R=upper_bound(tr[v].begin(),tr[v].end(),(node){r,0,0,0,0});
            sums+=L->cnt-R->cnt,sumd+=L->s-R->s;
        }
        if(w[u]<=r&&w[u]>=l)ans+=len;
        ans+=len*sums+sumd;
    }
    return ans;
}
int main(){
    read(n),read(m),read(AA),lg[0]=-1;
    for(int i=1;i<=n;i++)read(w[i]),ls[i]=w[i];
    sort(ls+1,ls+n+1),A=unique(ls+1,ls+n+1)-ls-1;
    for(int i=1;i<=n;i++)w[i]=lower_bound(ls+1,ls+A+1,w[i])-ls;
    for(int i=1;i<n;i++){
        int x,y,z;
        read(x),read(y),read(z);
        add(x,y,z),add(y,x,z);
    }
    init(),sum=n,son[0]=n+1,root=0;
    find_root(1,0),R=root,find_root(R,0);
    solve(root,0);
    LL lans=0;
    while(m--){
        int l,r,x;
        read(x),read(l),read(r);
        l=(l+lans)%AA,r=(r+lans)%AA;
        if(l>r)swap(l,r);
        l=lower_bound(ls+1,ls+A+1,l)-ls;
        r=upper_bound(ls+1,ls+A+1,r)-ls-1;
        printf("%lld\n",lans=query(l,r,x));
    }
}
posted @ 2018-12-19 08:49  Romeolong  阅读(156)  评论(0编辑  收藏  举报