题目大意

有一棵\(n\)(\(n\leq1.5*10^5\))个节点的二叉树,有点权\(x\),边权\(w\),\(q\)(\(q\leq2*10^5\))组询问,每组询问给出\(u,l,r\),求点权在\([l,r]\)的点到点\(u\)的距离之和,强制在线

题解

边分治:

边分树的每个点记一个数组,记录子树中每个点到重心边的端点的距离,按点的点权排序;查询时直接在点\(u\)边分树的每个祖先的兄弟的那个数组中二分。复杂度\(\Theta(n log^2 n)\)。

树剖+可持久化线段树:

发现点\(x\)到点\(u\)的距离相当于\(dep(u)+dep(x)-2*dep(lca)\),那么就可以把所有符合要求的点的祖先加上这个祖先到它的父亲的边权,这样所有符合要求的点到点\(u\)的距离是\((符合要求的点的深度之和)+dep(u)*(符号要求的点的个数)-2*(u和它的祖先加上了多少)\)

这个用可持久化线段树维护,将所有点按点权排序,依次加入;查询时用\(r版本-(l-1)版本\)。复杂度\(\Theta(n log^2 n)\)

代码

边分治

#include<algorithm>
#include<cmath>
#include<complex>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define rep(i,x,y) for(register int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
#define maxn 150010
#define maxm (maxn<<1)
#define view(u,k) for(int k=fir[u];k!=-1;k=nxt[k])
#define LL long long
#define ls son[u][0]
#define rs son[u][1]
#define mi (l+r>>1)
using namespace std;
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return x*f;
}
void write(LL x)
{
if(x==0){putchar('0'),putchar('\n');return;}
int f=0;char ch[20];
if(x<0)putchar('-'),x=-x;
while(x)ch[++f]=x%10+'0',x/=10;
while(f)putchar(ch[f--]);
putchar('\n');
return;
}
struct node{int x,k;}s[maxn];
int n,q,ag[maxn],vis[maxm],siz[maxn],fir[maxn],v[maxm],nxt[maxm],tp,cnt,wt,mnsz,nowsiz,st[20][maxm];
int lg[maxm],dfn[maxn],rt[maxn<<3],nd,ql,qr,son[maxn<<5][2],num[maxn<<5],to[maxn<<3],tim,bac[maxn],trsiz[maxn<<5],tmp;
LL w[maxm],dep[maxn],sum[maxn<<5],key[maxn<<5],dis[maxn],A,ans;
bool cmp(node x,node y){return x.k<y.k;}
void ade(int u1,int v1,int w1){v[cnt]=v1,w[cnt]=w1,nxt[cnt]=fir[u1],fir[u1]=cnt++;}
int LCA(int x,int y)
{
x=dfn[x],y=dfn[y];
if(x>y)swap(x,y);
int len=y-x+1;
return dis[st[lg[len]][x]]<dis[st[lg[len]][y-(1<<lg[len])+1]]?st[lg[len]][x]:st[lg[len]][y-(1<<lg[len])+1];
}
LL dist(int x,int y)
{
int lca=LCA(x,y);
return dis[x]+dis[y]-dis[lca]-dis[lca];
}
void getsiz(int u,int fa)
{
siz[u]=1;s[++tp].k=ag[u],s[tp].x=dep[u];
view(u,k)if(!vis[k]&&!vis[k^1]&&v[k]!=fa)
{
dep[v[k]]=dep[u]+w[k],getsiz(v[k],u),siz[u]+=siz[v[k]];
if(max(siz[v[k]],nowsiz-siz[v[k]])<mnsz)wt=k,mnsz=max(siz[v[k]],nowsiz-siz[v[k]]);;
}
}
int build(int l,int r)
{
int u=++nd;
if(l==r){sum[u]=s[l].x,key[u]=s[l].k,num[u]=s[l].x,trsiz[u]=1;return u;}
if(l<=mi-1)ls=build(l,mi-1);
if(mi+1<=r)rs=build(mi+1,r);
sum[u]=sum[ls]+sum[rs]+s[mi].x,key[u]=s[mi].k,num[u]=s[mi].x,trsiz[u]=trsiz[ls]+trsiz[rs]+1;
return u;
}
void add(int u,int lim,LL f)
{
if(!u)return;
if(key[u]>lim)return add(ls,lim,f);
if(ls)ans+=f*sum[ls],tmp+=f*trsiz[ls];ans+=f*num[u],tmp+=f;return add(rs,lim,f);
}
void getwt(int u,int sumsiz,int tr)
{
if(sumsiz==1){to[tr]=u,bac[u]=tr,rt[tr]=++nd,sum[nd]=num[nd]=0,trsiz[nd]=1,key[nd]=ag[u];return;}
dep[u]=0,tp=0,nowsiz=sumsiz,mnsz=n+1,getsiz(u,0);int now=wt,nxt1=v[now],nxt2=v[now^1];
if(tr!=1)
{
sort(s+1,s+tp+1,cmp),rt[tr]=build(1,tp),to[tr]=u;
}
vis[now]=vis[now^1]=tr;
if(siz[nxt1]>siz[nxt2])getwt(nxt1,nowsiz-siz[nxt2],tr<<1),getwt(nxt2,siz[nxt2],tr<<1|1);
else getwt(nxt2,nowsiz-siz[nxt1],tr<<1),getwt(nxt1,siz[nxt1],tr<<1|1);
}
void getans(int u)
{
int now=bac[u];ans=0;
while(now>>1)
{
tmp=0;
add(rt[now^1],qr,1),add(rt[now^1],ql-1,-1),ans+=(LL)tmp*dist(to[now^1],u);
now>>=1;
}
}
void getdep(int u,int fa)
{
dfn[u]=++tim;st[0][tim]=u;
view(u,k)if(v[k]!=fa){dis[v[k]]=dis[u]+w[k],getdep(v[k],u),st[0][++tim]=u;}
}
int main()
{
memset(fir,-1,sizeof(fir));
n=read(),q=read(),A=read();
rep(i,1,n)ag[i]=read();
rep(i,1,n-1)
{
int x=read(),y=read(),z=read();
ade(x,y,z),ade(y,x,z);
}
getdep(1,0);lg[0]=-1;
rep(i,1,tim)lg[i]=lg[i>>1]+1;
rep(k,1,lg[tim])for(int i=1;i+(1<<k)-1<=tim;++i)
st[k][i]=dis[st[k-1][i]]<dis[st[k-1][i+(1<<(k-1))]]?st[k-1][i]:st[k-1][i+(1<<(k-1))];
getwt(1,n,1);
while(q--)
{
int u=read();LL a=read(),b=read();
ql=min((a+ans)%A,(b+ans)%A),qr=max((a+ans)%A,(b+ans)%A);
getans(u),write(ans);
}
return 0;
}

树剖+可持久化线段树

#include<algorithm>
#include<cmath>
#include<complex>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define rep(i,x,y) for(register int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
#define maxn 150010
#define maxm (maxn<<1)
#define view(u,k) for(int k=fir[u];k!=-1;k=nxt[k])
#define LL long long
#define ls son[u][0]
#define rs son[u][1]
#define mi (l+r>>1)
#define ls2 (u2<<1)
#define rs2 (u2<<1|1)
using namespace std;
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return x*f;
}
void write(LL x)
{
if(x==0){putchar('0'),putchar('\n');return;}
int f=0;char ch[20];
if(x<0)putchar('-'),x=-x;
while(x)ch[++f]=x%10+'0',x/=10;
while(f)putchar(ch[f--]);
putchar('\n');
return;
}
struct node{int id,ag;}s[maxn];
int n,q,ag[maxn],siz[maxn],fir[maxn],v[maxm],nxt[maxm],cnt;
int fa[maxn],dfn[maxn],top[maxn],rt[maxn],nd,ql,qr,son[maxn<<6][2],wson[maxn],tim,bac[maxn],ver[maxn<<6],rnk[maxn];
LL w[maxm],dep[maxn],sum[maxn],tr[maxn<<6],mk[maxn<<6],ad[maxn<<2],tofa[maxn],A,ans;
void ade(int u1,int v1,int w1){v[cnt]=v1,w[cnt]=w1,nxt[cnt]=fir[u1],fir[u1]=cnt++;}
bool cmp1(node x,node y){return x.ag<y.ag;}
void getson(int u)
{
siz[u]=1;
view(u,k)if(v[k]!=fa[u])
{
fa[v[k]]=u,dep[v[k]]=dep[u]+w[k],tofa[v[k]]=w[k],getson(v[k]),siz[u]+=siz[v[k]];
if(!wson[u]||siz[wson[u]]<siz[v[k]])wson[u]=v[k];
}
}
void gettop(int u,int anc)
{
dfn[u]=++tim,bac[tim]=u,top[u]=anc;
if(wson[u])gettop(wson[u],anc);
view(u,k)if(v[k]!=wson[u]&&v[k]!=fa[u])gettop(v[k],v[k]);
}
void build(int u2,int l,int r){if(l==r){ad[u2]=tofa[bac[l]]<<1;return;}build(ls2,l,mi),build(rs2,mi+1,r),ad[u2]=ad[ls2]+ad[rs2];}
int add(int u,int u2,int l,int r,int x,int y,int vers)
{
int nu;
if(vers==ver[u]&&u)nu=u;
else nu=++nd,ver[nu]=vers;
mk[nu]=mk[u];son[nu][0]=ls,son[nu][1]=rs;
if(x<=l&&r<=y){mk[nu]++;tr[nu]=tr[ls]+tr[rs]+mk[nu]*ad[u2];return nu;}
if(x<=mi)son[nu][0]=add(ls,ls2,l,mi,x,y,vers);
if(y>mi)son[nu][1]=add(rs,rs2,mi+1,r,x,y,vers);
tr[nu]=tr[son[nu][0]]+tr[son[nu][1]]+mk[nu]*ad[u2];
return nu;
}
LL ask(int u,int u2,int l,int r,int x,int y,LL admk)
{
if(!u&&!admk)return 0;
if(x<=l&&r<=y)return tr[u]+ad[u2]*admk;
LL res=0;
if(x<=mi)res=ask(ls,ls2,l,mi,x,y,admk+mk[u]);
if(y>mi)res+=ask(rs,rs2,mi+1,r,x,y,admk+mk[u]);
return res;
}
void addrd(int u,int t1,int t2)
{
while(top[u]!=1)rt[t1]=add(rt[t2],1,1,n,dfn[top[u]],dfn[u],t1),u=fa[top[u]],t2=t1;
rt[t1]=add(rt[t2],1,1,n,dfn[top[u]],dfn[u],t1);
}
int getrnk(int x)
{
int l=1,r=n,ans=0;
while(l<=r){if(s[mi].ag<=x)ans=max(ans,mi),l=mi+1;else r=mi-1;}
return ans;
}
void getans(int u)
{
int pl=getrnk(ql-1),pr=getrnk(qr);ans=sum[pr]-sum[pl]+dep[u]*(LL)(pr-pl);
while(top[u]!=1)ans+=ask(rt[rnk[pl]],1,1,n,dfn[top[u]],dfn[u],0)-ask(rt[rnk[pr]],1,1,n,dfn[top[u]],dfn[u],0),u=fa[top[u]];
ans+=ask(rt[rnk[pl]],1,1,n,dfn[top[u]],dfn[u],0)-ask(rt[rnk[pr]],1,1,n,dfn[top[u]],dfn[u],0);
return;
}
int main()
{
memset(fir,-1,sizeof(fir));
n=read(),q=read(),A=read();
rep(i,1,n)ag[i]=read(),s[i].ag=ag[i],s[i].id=i;
rep(i,1,n-1){int x=read(),y=read(),z=read();ade(x,y,z),ade(y,x,z);}
sort(s+1,s+n+1,cmp1),ver[0]=-1,getson(1),gettop(1,1),build(1,1,n);
rep(i,1,n)
{
sum[i]=sum[i-1]+dep[s[i].id];
if(i!=1&&s[i].ag==s[i-1].ag){rnk[i]=rnk[i-1],addrd(s[i].id,rnk[i],rnk[i]);}
else{rnk[i]=rnk[i-1]+1,addrd(s[i].id,rnk[i],rnk[i-1]);}
}
while(q--)
{
int u=read();LL a=read(),b=read();
ql=min((a+ans)%A,(b+ans)%A),qr=max((a+ans)%A,(b+ans)%A);
getans(u),write(ans);
}
return 0;
}

并不对劲的bzoj4012:loj2116:p3241: [HNOI2015]开店的更多相关文章

  1. 洛谷 P3241 [HNOI2015]开店 解题报告

    P3241 [HNOI2015]开店 题目描述 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱. 这样的想法当然非 ...

  2. P3241 [HNOI2015]开店 动态点分治

    \(\color{#0066ff}{ 题目描述 }\) 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱. 这样的想 ...

  3. luogu P3241 [HNOI2015]开店

    传送门 (下面记年龄为\(a_x\))题目要求的是\[\sum_{x=1}^{n} [a_x\in [l,r]]*dis(x,u)=\sum_{x=1}^{n} [a_x\in [l,r]]*de_x ...

  4. P3241 [HNOI2015]开店

    题解:动态点分治 建立点分树 每个点维护点分树子树内节点到这个节点和父亲节点距离的前缀和 二分查找锁定合法区间 对每个祖先分治中心查询路径和然后减去不合法子树内的路径和 注意:求大量LCA时用树剖 不 ...

  5. [BZOJ4012][HNOI2015]开店(动态点分治,树链剖分)

    4012: [HNOI2015]开店 Time Limit: 70 Sec  Memory Limit: 512 MBSubmit: 2168  Solved: 947[Submit][Status] ...

  6. 【BZOJ4012】[HNOI2015]开店 动态树分治+二分

    [BZOJ4012][HNOI2015]开店 Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点 ...

  7. [loj2116]「HNOI2015」开店 动态点分治

    4012: [HNOI2015]开店 Time Limit: 70 Sec  Memory Limit: 512 MBSubmit: 2452  Solved: 1089[Submit][Status ...

  8. [HNOI2015]开店 树链剖分,主席树

    [HNOI2015]开店 LG传送门 蒟蒻表示不会动态淀粉质. 先把点按年龄排序, 设\(dis[i]\)表示\(i\)到根的距离. 把我们要算的东西稍微变下形:\(ans\) \[ = \sum \ ...

  9. BZOJ4012 [HNOI2015]开店

    Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现 ...

随机推荐

  1. NYOJ301-递推求值

    递推求值 nyoj上矩阵专题里的10道题水了AC率最高的5道,惭愧,还不是完全自己写的,用了几乎两周的时间.模板题我是有自信写出来的,但对于高级一点的矩阵构造,我还是菜的抠脚. 这题感谢MQL大哥和她 ...

  2. irules事件和命令

  3. mysql针对转义字符的模糊搜索

    由于urlencode之后会产生很多'%'符号,这个符号在mysql模糊搜索中代表任意字符,显示会出现问题,例如 name字段经过urlencode之后变成‘%E6%9D%8E%E5%87%A1’,如 ...

  4. C#高级编程第9版 第二章 核心C# 读后笔记

    System命名空间包含了最常用的.NET类型.对应前面第一章的.NET基类.可以这样理解:.NET类提供了大部分的功能,而C#语言本身是提供了规则. pseudo-code,哈哈,秀逗code.伪代 ...

  5. python学习之 -- 数据序列化

    json / pickle 数据序列化 序列化定义:把变量从内存中变成可存储或传输的过程称为序列化.反序列化:把变量内容从序列化的对象重新读到内存里称为反序列胡. 序列化模块之--pickle使用注意 ...

  6. 一致性哈希算法-----> 解决memecache 服务器扩容后的数据丢失。

    1 基本场景 比如你有 N 个 cache 服务器(后面简称 cache ),那么如何将一个对象 object 映射到 N 个 cache 上呢,你很可能会采用类似下面的通用方法计算 object 的 ...

  7. Match the string--hdu1797(模拟)

    http://acm.hdu.edu.cn/showproblem.php?pid=1797 就是模拟 我的思路是标记aba 和h的位置 然后就判断是否正确  就行了 还有就是  最后 fkfkfkf ...

  8. 2017CodeM复赛

    A.配对游戏(loj6191) 题目: https://loj.ac/problem/6191 分析: g[i][j]表示前i个位置尽可能合并,合并到最后右边剩下j个>,这样情况的概率 那么g[ ...

  9. java开发面试大全刷题整理

    题目源自Java团长公众号,内容个人整理,来源于各大博客,未经允许,不准摘抄,仅供分享,不做商业使用. 本分享多数为浅层知识体系,更为底层的还请自行多写写代码,若有不对之处,望广大的人才指点,不喜勿喷 ...

  10. java.net.URISyntaxException的解决办法

    java.net.URISyntaxException的解决办法 近日在用HttpClient访问抓取汇率时,为了省力,直接采用 String url = "http://api.liqwe ...