bzoj 4012 [HNOI2015]开店 【树链剖分】

这道题好像各位神犇都是用动态树分治写的,我这么弱只能用树剖水一水了。

dis(x,y)=dis(1,x)+dis(1,y)-dis(1,lca(x,y))

前两个都是定值,求第三项就行了。

每个点x维护不在重链上的子节点的个数*dis(1,x),查询显然,再yy一些别的东西就可以了。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>


#define ll long long
#define inf 1e9
#define eps 1e-10
#define md
#define N 150010
#define TR 20000000
using namespace std;
struct yts { int x,t,l,ne;} e[2*N];
int n,td;
int num,dfs_cnt,cnt;
int dat[N],v[N],dep[N],sz[N],son[N],fa[N][20],pos[N],top[N],low[N],right[N],dis[N],root[N],s_sz[N];
ll s_dis[N];
ll sum[TR];
int size[TR],ch[TR][2],qs[TR];
struct AA { int age,pos;} a[N];
bool cmp(AA a,AA b) { return a.age<b.age;}


void lisanhua()
{
<span style="white-space:pre">	</span>sort(a+1,a+n+1,cmp);
<span style="white-space:pre">	</span>a[0].age=-1; int now=-1; dat[0]=-1;
<span style="white-space:pre">	</span>for (int i=1;i<=n;i++)
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>if (a[i].age!=now) { dat[++td]=a[i].age; now=a[i].age;}
<span style="white-space:pre">		</span>a[i].age=td;
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>dat[td+1]=inf;
<span style="white-space:pre">	</span>//for (int i=1;i<=td;i++) printf("%d ",dat[i]); printf("\n");
}
void put(int x,int y,int l)
{
<span style="white-space:pre">	</span>num++; e[num].x=x; e[num].t=y; e[num].l=l;
<span style="white-space:pre">	</span>e[num].ne=v[x]; v[x]=num;
}
void dfs1(int x)
{
<span style="white-space:pre">	</span>sz[x]=1; son[x]=0;
<span style="white-space:pre">	</span>for (int i=v[x];i;i=e[i].ne)
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>int y=e[i].t;
<span style="white-space:pre">		</span>if (y!=fa[x][0])
<span style="white-space:pre">		</span>{
<span style="white-space:pre">			</span>fa[y][0]=x; dep[y]=dep[x]+1; dis[y]=dis[x]+e[i].l;
<span style="white-space:pre">			</span>dfs1(y);
<span style="white-space:pre">			</span>sz[x]+=sz[y]; if (sz[y]>sz[son[x]]) son[x]=y;
<span style="white-space:pre">		</span>}
<span style="white-space:pre">	</span>}
}


void dfs2(int x,int f)
{
<span style="white-space:pre">	</span>pos[x]=++dfs_cnt; top[x]=f;
<span style="white-space:pre">	</span>if (son[x])
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>dfs2(son[x],f);
<span style="white-space:pre">		</span>low[x]=low[son[x]];
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>else low[x]=pos[x];
<span style="white-space:pre">	</span>for (int i=v[x];i;i=e[i].ne)
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>int y=e[i].t;
<span style="white-space:pre">		</span>if (y!=fa[x][0]&&y!=son[x])
<span style="white-space:pre">		</span>  dfs2(y,y);
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>right[x]=dfs_cnt;
}


int find1(int x)//最小的大于等于x的。
{
<span style="white-space:pre">	</span>int l=1,r=td+1;
<span style="white-space:pre">	</span>while (l!=r)
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>int mid=(l+r)>>1;
<span style="white-space:pre">		</span>if (dat[mid]>=x) r=mid; else l=mid+1;
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>return l;
}


int find2(int x)//最大的小于等于x的。
{
<span style="white-space:pre">	</span>int l=0,r=td;
<span style="white-space:pre">	</span>while (l!=r)
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>int mid=(l+r+1)>>1;
<span style="white-space:pre">		</span>if (dat[mid]<=x) l=mid; else r=mid-1;
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>return l;
}


void build_lca()
{
<span style="white-space:pre">	</span>for (int j=1;j<=18;j++)
<span style="white-space:pre">	</span>  for (int i=1;i<=n;i++)
<span style="white-space:pre">	</span>    if (fa[i][j-1]) fa[i][j]=fa[fa[i][j-1]][j-1];
}


int lca(int x,int y)
{
<span style="white-space:pre">	</span>if (dep[x]<dep[y]) swap(x,y); 
<span style="white-space:pre">	</span>int t=dep[x]-dep[y];
<span style="white-space:pre">	</span>for (int i=18;i>=0;i--)
<span style="white-space:pre">	</span>  if (t&(1<<i)) x=fa[x][i];
<span style="white-space:pre">	</span>if (x==y) return x;
<span style="white-space:pre">	</span>for (int i=18;i>=0;i--)
<span style="white-space:pre">	</span>  if (fa[x][i]!=fa[y][i])
<span style="white-space:pre">	</span>    x=fa[x][i],y=fa[y][i];
<span style="white-space:pre">	</span>return fa[x][0];
}


void insert_sz(int &i,int pre,int l,int r,int x)
{
<span style="white-space:pre">	</span>i=++cnt;
<span style="white-space:pre">	</span>size[i]=size[pre]+1; sum[i]=sum[pre]; qs[i]=qs[pre];
<span style="white-space:pre">	</span>if (l==r) return;
<span style="white-space:pre">	</span>int mid=(l+r)>>1;
<span style="white-space:pre">	</span>if (x<=mid)
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>insert_sz(ch[i][0],ch[pre][0],l,mid,x);
<span style="white-space:pre">		</span>ch[i][1]=ch[pre][1];
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>else
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>insert_sz(ch[i][1],ch[pre][1],mid+1,r,x);
<span style="white-space:pre">		</span>ch[i][0]=ch[pre][0];
<span style="white-space:pre">	</span>}
}


void insert(int &i,int pre,int l,int r,int x,int dis)
{
<span style="white-space:pre">	</span>i=++cnt;
<span style="white-space:pre">	</span>sum[i]=sum[pre]+dis; size[i]=size[pre]; qs[i]=qs[pre]+1;
<span style="white-space:pre">	</span>if (l==r) return;
<span style="white-space:pre">	</span>int mid=(l+r)>>1;
<span style="white-space:pre">	</span>if (x<=mid)
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>insert(ch[i][0],ch[pre][0],l,mid,x,dis);
<span style="white-space:pre">		</span>ch[i][1]=ch[pre][1];
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>else
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>insert(ch[i][1],ch[pre][1],mid+1,r,x,dis);
<span style="white-space:pre">		</span>ch[i][0]=ch[pre][0];
<span style="white-space:pre">	</span>}
}
<span style="white-space:pre">	</span>
ll query_sz(int L,int R,int l,int r,int ql,int qr)
{
<span style="white-space:pre">	</span>if (ql<=l&&r<=qr) return size[R]-size[L];
<span style="white-space:pre">	</span>int mid=(l+r)>>1;
<span style="white-space:pre">	</span>if (qr<=mid) return query_sz(ch[L][0],ch[R][0],l,mid,ql,qr);
<span style="white-space:pre">	</span>if (mid+1<=ql) return query_sz(ch[L][1],ch[R][1],mid+1,r,ql,qr);
<span style="white-space:pre">	</span>return query_sz(ch[L][0],ch[R][0],l,mid,ql,qr)+query_sz(ch[L][1],ch[R][1],mid+1,r,ql,qr);
}


ll query(int L,int R,int l,int r,int ql,int qr)
{
<span style="white-space:pre">	</span>if (ql<=l&&r<=qr) return sum[R]-sum[L];
<span style="white-space:pre">	</span>int mid=(l+r)>>1;
<span style="white-space:pre">	</span>if (qr<=mid) return query(ch[L][0],ch[R][0],l,mid,ql,qr);
<span style="white-space:pre">	</span>if (mid+1<=ql) return query(ch[L][1],ch[R][1],mid+1,r,ql,qr);
<span style="white-space:pre">	</span>return query(ch[L][0],ch[R][0],l,mid,ql,qr)+query(ch[L][1],ch[R][1],mid+1,r,ql,qr);
}


ll query_line(int L,int R,int l,int r,int ql,int qr)
{
<span style="white-space:pre">	</span>if (ql<=l&&r<=qr) return qs[R]-qs[L];
<span style="white-space:pre">	</span>int mid=(l+r)>>1;
<span style="white-space:pre">	</span>if (qr<=mid) return query_line(ch[L][0],ch[R][0],l,mid,ql,qr);
<span style="white-space:pre">	</span>if (mid+1<=ql) return query_line(ch[L][1],ch[R][1],mid+1,r,ql,qr);
<span style="white-space:pre">	</span>return query_line(ch[L][0],ch[R][0],l,mid,ql,qr)+query_line(ch[L][1],ch[R][1],mid+1,r,ql,qr);
}


int main()
{
#ifndef ONLINE_JUDGE
<span style="white-space:pre">	</span>freopen("data.in","r",stdin); freopen("b.out","w",stdout);
#endif
<span style="white-space:pre">	</span>int Q,A;
<span style="white-space:pre">	</span>scanf("%d%d%d",&n,&Q,&A);
<span style="white-space:pre">	</span>for (int i=1;i<=n;i++)
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>scanf("%d",&a[i].age);
<span style="white-space:pre">		</span>a[i].pos=i;
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>for (int i=1;i<n;i++)
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>int x,y,l;
<span style="white-space:pre">		</span>scanf("%d%d%d",&x,&y,&l);
<span style="white-space:pre">		</span>put(x,y,l); put(y,x,l);
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>dep[1]=1; dfs1(1); dfs2(1,1); build_lca(); <span style="white-space:pre">	</span>
<span style="white-space:pre">	</span>lisanhua();
<span style="white-space:pre">	</span>int pre=0;
<span style="white-space:pre">	</span>for (int i=1;i<=n;i++)
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>int x=a[i].pos;
<span style="white-space:pre">		</span>insert_sz(root[a[i].age],pre,1,n,pos[x]); pre=root[a[i].age];
<span style="white-space:pre">		</span>s_sz[a[i].age]++; s_dis[a[i].age]+=dis[x];
<span style="white-space:pre">		</span>while (x)
<span style="white-space:pre">		</span>{
<span style="white-space:pre">			</span>insert(root[a[i].age],pre,1,n,pos[x],dis[x]); pre=root[a[i].age];
<span style="white-space:pre">			</span>x=fa[top[x]][0];
<span style="white-space:pre">		</span>}
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>for (int i=1;i<=td;i++) s_sz[i]+=s_sz[i-1],s_dis[i]+=s_dis[i-1];
<span style="white-space:pre">	</span>ll ans=0;
<span style="white-space:pre">	</span>for (int i=1;i<=Q;i++)
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>int u,x,y;
<span style="white-space:pre">		</span>scanf("%d%d%d",&u,&x,&y);
<span style="white-space:pre">		</span>int L=(ans+x)%A,R=(ans+y)%A;
<span style="white-space:pre">		</span>if (L>R) swap(L,R);
<span style="white-space:pre">		</span>L=find1(L); R=find2(R);
<span style="white-space:pre">		</span>if (L>td||R<1||L>R)
<span style="white-space:pre">		</span>{
<span style="white-space:pre">			</span>ans=0; printf("0\n");
<span style="white-space:pre">			</span>continue;
<span style="white-space:pre">		</span>}
<span style="white-space:pre">		</span>int rtL=root[L-1],rtR=root[R];
<span style="white-space:pre">		</span>x=u;
<span style="white-space:pre">		</span>ans=((ll)dis[x])*(s_sz[R]-s_sz[L-1])+s_dis[R]-s_dis[L-1];
<span style="white-space:pre">		</span>ll jian=0;
<span style="white-space:pre">		</span>while (x)
<span style="white-space:pre">		</span>{
<span style="white-space:pre">			</span>jian+=query(rtL,rtR,1,n,pos[top[x]],pos[x]);
<span style="white-space:pre">			</span>if (son[x]) jian+=query_line(rtL,rtR,1,n,pos[x]+1,low[x])*dis[x];
<span style="white-space:pre">			</span>x=top[x]; y=fa[x][0];
<span style="white-space:pre">			</span>if (y) jian-=query_sz(rtL,rtR,1,n,pos[x],right[x])*dis[y];
<span style="white-space:pre">			</span>x=y;
<span style="white-space:pre">		</span>}
<span style="white-space:pre">		</span>ans=ans-jian*2;
<span style="white-space:pre">		</span>printf("%lld\n",ans);
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值