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));
}
}