解题:HNOI 2015 开店

题面

根据树上距离的计算方法,可以先把答案化成$\sum dep_i+n*dep_u-\sum 2*dep[LCA(i,u)]$的形式,然后维护$\sum 2*dep[LCA(i,u)]$

把妖怪们按年龄排序,轻重剖分后插入每个点到根的路径,记录经过次数,询问也是往根跳然后每次统计边权*次数。

可持久化线段树+差分

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 using namespace std;
  5 const int N=300005,M=1e7+70,inf=1e9;
  6 int root[N],son[M][2],num[M];
  7 int p[N],noww[N],goal[N],val[N];
  8 int siz[N],far[N],imp[N],top[N],dfn[N];
  9 long long dis[N],sum1[N],sum2[N],sum[M],ans;
 10 int n,m,nm,rt,t1,t2,t3,rot,cnt,tot;
 11 struct a
 12 {
 13     int age,idx;
 14 }mon[N];
 15 bool operator < (a x,a y)
 16 {
 17     return x.age==y.age?x.idx<y.idx:x.age<y.age;
 18 }
 19 void Link(int f,int t,int v)
 20 {
 21     noww[++cnt]=p[f],p[f]=cnt;
 22     goal[cnt]=t,val[cnt]=v;
 23     noww[++cnt]=p[t],p[t]=cnt;
 24     goal[cnt]=f,val[cnt]=v;
 25 }
 26 void DFS(int nde,int fth)
 27 {
 28     int tmp=0;
 29     siz[nde]=1,far[nde]=fth;
 30     for(int i=p[nde],g;i;i=noww[i])
 31         if((g=goal[i])!=fth)
 32         {
 33             dis[g]=dis[nde]+val[i];
 34             DFS(g,nde),siz[nde]+=siz[g];
 35             if(siz[g]>tmp) tmp=siz[g],imp[nde]=g;
 36         }
 37 }
 38 void Mark(int nde,int tpp)
 39 {
 40     top[nde]=tpp,dfn[nde]=++tot;
 41     sum1[tot]=dis[nde]-dis[far[nde]];
 42     if(imp[nde])
 43     {
 44         Mark(imp[nde],tpp);
 45         for(int i=p[nde],g;i;i=noww[i])
 46             if((g=goal[i])!=far[nde]&&g!=imp[nde]) Mark(g,g);
 47     }
 48 }
 49 
 50 int Insert(int pre,int l,int r,int ll,int rr)
 51 {
 52     int nde=++tot;
 53     son[nde][0]=son[pre][0];
 54     son[nde][1]=son[pre][1];
 55     num[nde]=num[pre],sum[nde]=sum[pre];
 56     if(l==ll&&r==rr) num[nde]++;
 57     else
 58     {
 59         int mid=(l+r)>>1;
 60         sum[nde]+=sum1[rr]-sum1[ll-1];
 61         if(mid>=rr) son[nde][0]=Insert(son[pre][0],l,mid,ll,rr);
 62         else if(mid<ll) son[nde][1]=Insert(son[pre][1],mid+1,r,ll,rr);
 63         else son[nde][0]=Insert(son[pre][0],l,mid,ll,mid),
 64              son[nde][1]=Insert(son[pre][1],mid+1,r,mid+1,rr);
 65     }
 66     return nde;
 67 }
 68 long long Query(int nde,int l,int r,int ll,int rr)
 69 {
 70     long long ret=(sum1[rr]-sum1[ll-1])*num[nde];
 71     if(l==ll&&r==rr)
 72         return ret+sum[nde];
 73     else
 74     {
 75         int mid=(l+r)>>1;
 76         if(mid>=rr) return ret+Query(son[nde][0],l,mid,ll,rr);
 77         else if(mid<ll) return ret+Query(son[nde][1],mid+1,r,ll,rr);
 78         else return ret+Query(son[nde][0],l,mid,ll,mid)+Query(son[nde][1],mid+1,r,mid+1,rr);
 79     }
 80 }
 81 
 82 int Change(int nde)
 83 {
 84     while(top[nde]!=rt)
 85         rot=Insert(rot,1,n,dfn[top[nde]],dfn[nde]),nde=far[top[nde]];
 86     return rot=Insert(rot,1,n,1,dfn[nde]);
 87 }
 88 long long Ask(int trt,int nde)
 89 {
 90     long long ret=0;
 91     while(top[nde]!=rt)
 92         ret+=Query(trt,1,n,dfn[top[nde]],dfn[nde]),nde=far[top[nde]];
 93     return ret+Query(trt,1,n,1,dfn[nde]);
 94 }
 95 
 96 int main()
 97 {
 98     scanf("%d%d%d",&n,&m,&nm),rt=1;
 99     for(int i=1;i<=n;i++)
100         scanf("%d",&t1),mon[i]=(a){t1,i};
101     sort(mon+1,mon+1+n);
102     for(int i=1;i<n;i++)
103         scanf("%d%d%d",&t1,&t2,&t3),Link(t1,t2,t3);
104     DFS(1,0),Mark(1,1);
105     for(int i=1;i<=n;i++)
106         sum1[i]+=sum1[i-1],sum2[i]=sum2[i-1]+dis[mon[i].idx];
107     for(int i=1;i<=n;i++)    
108         root[i]=Change(mon[i].idx);
109     for(int i=1;i<=m;i++)
110     {
111         scanf("%d%d%d",&t1,&t2,&t3);
112         t2=(ans+t2)%nm,t3=(ans+t3)%nm;
113         if(t2>t3) swap(t2,t3);
114         int ll=lower_bound(mon+1,mon+1+n,(a){t2,0})-mon;
115         int rr=upper_bound(mon+1,mon+1+n,(a){t3,inf})-mon-1;
116     //    printf("%d==%d==%d==%d==%d==",ll,rr,dis[t1]*(rr-ll+1),sum2[rr]-sum2[ll-1],2*(Ask(root[rr],t1)-Ask(root[ll-1],t1)));
117         printf("%lld\n",ans=dis[t1]*(rr-ll+1)+sum2[rr]-sum2[ll-1]-2*(Ask(root[rr],t1)-Ask(root[ll-1],t1)));
118     }
119     return 0;
120 }
View Code

猜你喜欢

转载自www.cnblogs.com/ydnhaha/p/10534782.html
今日推荐