1. 程式人生 > >2019.01.02-dtoj2293-幻想鄉開店(shop)

2019.01.02-dtoj2293-幻想鄉開店(shop)

題目描述:

 風見幽香有一個好朋友叫八雲紫,她們經常一起看星星看月亮從詩詞歌賦談到

人生哲學。最近她們靈機一動,打算在幻想鄉開一家小店來做生意賺點錢。這樣的 想法當然非常好啦,但是她們也發現她們面臨著一個問題,那就是店開在哪裡,面 向什麼樣的人群。很神奇的是,幻想鄉的地圖是一個樹形結構,幻想鄉一共有 n 個地方,編號為 1 到 n,被 n-1 條帶權的邊連線起來。每個地方都住著一個妖怪, 其中第 i 個地方的妖怪年齡是 x_i。妖怪都是些比較喜歡安靜的傢伙,所以它們並 不希望和很多妖怪相鄰。所以這個樹所有頂點的度數都小於或等於 3。妖怪和人一 樣,興趣點隨著年齡的變化自然就會變化,比如我們的 18 歲少女幽香和八雲紫就 比較喜歡可愛的東西。幽香通過研究發現,基本上妖怪的興趣只跟年齡有關,所以 幽香打算選擇一個地方 u(u為編號),然後在 u開一家面向年齡在 L到R 之間(即 年齡大於等於 L、小於等於 R)的妖怪的店。也有可能 u這個地方離這些妖怪比較 遠,於是幽香就想要知道所有年齡在 L 到 R 之間的妖怪,到點 u 的距離的和是多 少(妖怪到 u 的距離是該妖怪所在地方到 u 的路徑上的邊的權之和) ,幽香把這個 稱為這個開店方案的方便值。幽香她們還沒有決定要把店開在哪裡,八雲紫倒是準 備了很多方案,於是幽香想要知道,對於每個方案,方便值是多少呢。

演算法標籤:樹剖,主席樹

思路:

考慮如果沒有年齡限制,答案為總點數*d[u]+∑d[i]-∑d[lca(u,i)]。 加上年齡限制,前兩個值比較好維護,對於第三個我們考慮用主席樹,對於每一個lca,相當於我們把i到根的路徑覆蓋,取u到根的路徑上被覆蓋的權值和,即為答案,用主席樹統計。 第一次寫樹剖套主席樹呢

以下程式碼:

#include<bits/stdc++.h>
#define il inline
#define LL long long
#define _(d) while(d(isdigit(ch=getchar())))
using
namespace std; const int N=150005;LL ans,s[N],sd[N]; struct node{int age,id;}b[N];struct data{int l,r,num;LL sum;}t[N*100]; int sz[N],fa[N],son[N],top[N],dfn[N],num[N],cnt,tag[N],c[N],A; int n,q,head[N],ne[N<<1],to[N<<1],w[N<<1],val[N],tot,nt,dist[N],rt[N]; il int read(){int x;char
ch;_(!);x=ch^48;_()x=(x<<1)+(x<<3)+(ch^48);return x;} bool cmp(node t1,node t2){return t1.age<t2.age||(t1.age==t2.age&&t1.id<t2.id);} il void insert(int x,int y,int z){ne[++cnt]=head[x];head[x]=cnt;to[cnt]=y;w[cnt]=z;} il void dfs1(int x){ sz[x]=1;int maxn=-1; for(int i=head[x];i;i=ne[i]){ if(fa[x]==to[i])continue; fa[to[i]]=x;dist[to[i]]=dist[x]+w[i]; dfs1(to[i]);sz[x]+=sz[to[i]];val[to[i]]=w[i]; if(maxn<sz[to[i]])son[x]=to[i],maxn=sz[to[i]]; } } il void dfs2(int x,int root){ dfn[x]=++tot;num[tot]=x;top[x]=root; if(!son[x])return;dfs2(son[x],root); for(int i=head[x];i;i=ne[i]){ if(dfn[to[i]])continue; dfs2(to[i],to[i]); } } il void Ia(int &x,int y,int l,int r,int ql,int qr){ t[x=++nt]=t[y]; if(ql==l&&r==qr){t[x].num++;return;} int mid=(l+r)>>1;t[x].sum+=s[qr]-s[ql-1]; if(qr<=mid)Ia(t[x].l,t[y].l,l,mid,ql,qr); else if(mid<ql)Ia(t[x].r,t[y].r,mid+1,r,ql,qr); else Ia(t[x].l,t[y].l,l,mid,ql,mid),Ia(t[x].r,t[y].r,mid+1,r,mid+1,qr); } il void Ta(int u,int x){ rt[u]=rt[u-1]; while(x>1){ Ia(rt[u],rt[u],1,n,dfn[top[x]],dfn[x]); x=fa[top[x]]; } } il LL Iq(int x,int y,int l,int r,int ql,int qr){ LL res=1ll*(t[y].num-t[x].num)*(s[qr]-s[ql-1]); if(ql==l&&r==qr)return res+t[y].sum-t[x].sum; if(!x&&!y)return 0;int mid=(l+r)>>1; if(qr<=mid)return res+Iq(t[x].l,t[y].l,l,mid,ql,qr); if(mid<ql)return res+Iq(t[x].r,t[y].r,mid+1,r,ql,qr); return res+Iq(t[x].l,t[y].l,l,mid,ql,mid)+Iq(t[x].r,t[y].r,mid+1,r,mid+1,qr); } il LL Tq(int x,int y,int u){ LL res=0; while(u>1){ res+=Iq(x,y,1,n,dfn[top[u]],dfn[u]); u=fa[top[u]]; } return res; } int main() { n=read();q=read();A=read(); for(int i=1;i<=n;i++)b[i].age=read(),b[i].id=i; sort(b+1,b+1+n,cmp); for(int i=1;i<n;i++){ int x=read(),y=read(),z=read(); insert(x,y,z);insert(y,x,z); } dfs1(1);dfs2(1,1); for(int i=1;i<=n;i++)s[i]=s[i-1]+val[num[i]],sd[i]=sd[i-1]+dist[b[i].id]; for(int i=1;i<=n;i++)Ta(i,b[i].id),c[i]=b[i].age; while(q--){ int u=read(),l=read(),r=read(); l=(1ll*l+ans)%A;r=(1ll*r+ans)%A; if(l>r)swap(l,r); l=lower_bound(c+1,c+1+n,l)-c; r=upper_bound(c+1,c+1+n,r)-c-1; ans=sd[r]-sd[l-1]+1ll*(r-l+1)*dist[u]-2*Tq(rt[l-1],rt[r],u); printf("%lld\n",ans); } return 0; }
View Code