BZOJ4012 [HNOI2015]開店 (動態點分治)

Description

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

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

Input

 第一行三個用空格分開的數 n、Q和A,表示樹的大小、開店的方案個數和妖node

怪的年齡上限。 
第二行n個用空格分開的數 x_一、x_二、…、x_n,x_i 表示第i 個地點妖怪的年
齡,知足0<=x_i<A。(年齡是能夠爲 0的,例如剛出生的妖怪的年齡爲 0。) 
接下來 n-1 行,每行三個用空格分開的數 a、b、c,表示樹上的頂點 a 和 b 之
間有一條權爲c(1 <= c <= 1000)的邊,a和b 是頂點編號。 
接下來Q行,每行三個用空格分開的數 u、 a、 b。對於這 Q行的每一行,用 a、
b、A計算出 L和R,表示詢問「在地方 u開店,面向妖怪的年齡區間爲[L,R]的方
案的方便值是多少」。對於其中第 1 行,L 和 R 的計算方法爲:L=min(a%A,b%A), 
R=max(a%A,b%A)。對於第 2到第 Q行,假設前一行獲得的方便值爲 ans,那麼當
前行的 L 和 R 計算方法爲: L=min((a+ans)%A,(b+ans)%A), 
R=max((a+ans)%A,(b+ans)%A)。 
 

Output

對於每一個方案,輸出一行表示方便值。 ios

 

Sample Input

10 10 10 
0 0 7 2 1 4 7 7 7 9 
1 2 270 
2 3 217 
1 4 326 
2 5 361 
4 6 116 
3 7 38 
1 8 800 
6 9 210 
7 10 278 
8 9 8 
2 8 0 
9 3 1 
8 0 8 
4 2 7 
9 7 3 
4 7 0 
2 2 7 
3 2 1 
2 3 4

Sample Output

1603 
957 
7161 
9466 
3232 
5223 
1879 
1669 
1282 
0

HINT

 

 知足 n<=150000,Q<=200000。對於全部數據,知足 A<=10^9git


題解spa

  這題正解是動態點分治(不過聽說主席樹+樹鏈剖分跑得更快?)code

  若是不知道什麼是動態點分的能夠去看看幻想鄉的戰略遊戲->蒟蒻的題解htm

  這一道題,咱們考慮對於每個點分樹上的點維護什麼。咱們記錄三個值,$sz_0$表示子樹內的點數之和,$sz_1$表示子樹內全部點到其的距離之和,$sz_2$表示子樹內全部點到其父親的距離之和。那麼考慮咱們在跳點分樹的時候要如何維護答案呢?很明顯$sz_1[u]+\sum sz_1[fa]-sz_2[p]+(sz_0[fa]-sz_0[p])*dist(fa,u)$就是在點分樹上與$u$的$LCA$是$fa$的全部點的距離之和,其中$fa$爲$p$的父親,$p$爲從$u$不斷跳父親直到根,那麼只要不斷枚舉$fa$,並不斷往上跳並維護答案就能夠了。blog

  然而上面只是爲了方便理解,由於具體的計算不是這樣的。咱們對於$u$點內部的貢獻能夠直接計算,而後考慮往上跳。在上述的式子中若是一個點$p$有$fa$,那麼答案就要減去$sz_0[p]*dist(fa,u)+sz_2[p]$,若是一個點不是$u$那麼答案就要加上$sz_0[p]+dist(p,u)$,而後每個點都要加上本身的$sz_1$。按這個規律在跳點分樹的時候不斷加就行了遊戲

  而後考慮怎麼在$[l,r]$以內,很明顯能夠搞一個差分,把每個節點在點分樹上的子樹內的全部年齡的距離之和加起來,在作前綴和,那麼在年齡$[l,r]$的人數就是$[1,r]-[1,l-1]$ip

  1 //minamoto
  2 #include<cstdio>
  3 #include<iostream>
  4 #include<cstring>
  5 #include<vector>
  6 #include<algorithm>
  7 #define ll long long
  8 #define N 150005
  9 using namespace std;
 10 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
 11 char buf[1<<21],*p1=buf,*p2=buf;
 12 template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
 13 inline int read(){
 14     #define num ch-'0'
 15     char ch;bool flag=0;int res;
 16     while(!isdigit(ch=getc()))
 17     (ch=='-')&&(flag=true);
 18     for(res=num;isdigit(ch=getc());res=res*10+num);
 19     (flag)&&(res=-res);
 20     #undef num
 21     return res;
 22 }
 23 char sr[1<<21],z[20];int C=-1,Z;
 24 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
 25 inline void print(ll x){
 26     if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;
 27     while(z[++Z]=x%10+48,x/=10);
 28     while(sr[++C]=z[Z],--Z);sr[++C]='\n';
 29 }
 30 int head[N],Next[N<<1],ver[N<<1],edge[N<<1];
 31 int n,tot,val[N],q,maxn;
 32 int st[N<<1][19],d[N],dfn[N],num,bin[25],tp,logn[N<<1];
 33 inline void add(int u,int v,int e){
 34     ver[++tot]=v,Next[tot]=head[u],head[u]=tot,edge[tot]=e;
 35     ver[++tot]=u,Next[tot]=head[v],head[v]=tot,edge[tot]=e;
 36 }
 37 inline void ST(){
 38     for(int j=1;j<=tp;++j)
 39     for(int i=1;i+bin[j]-1<=(n<<1);++i)
 40     st[i][j]=min(st[i][j-1],st[i+bin[j-1]][j-1]);
 41 }
 42 void dfs1(int u,int fa){
 43     st[dfn[u]=++num][0]=d[u];
 44     for(int i=head[u];i;i=Next[i]){
 45         int v=ver[i];
 46         if(v==fa) continue;
 47         d[v]=d[u]+edge[i],dfs1(v,u),st[++num][0]=d[u];
 48     }
 49 }
 50 int fa[N],sz[N],son[N],size,rt;bool vis[N];
 51 void dfs2(int u,int fa){
 52     sz[u]=1,son[u]=0;
 53     for(int i=head[u];i;i=Next[i]){
 54         int v=ver[i];
 55         if(vis[v]||v==fa) continue;
 56         dfs2(v,u),sz[u]+=sz[v],cmax(son[u],sz[v]);
 57     }
 58     cmax(son[u],size-sz[u]);
 59     if(son[u]<son[rt]) rt=u;
 60 }
 61 inline ll dis(int a,int b){
 62     if(dfn[a]>dfn[b]) a^=b^=a^=b;
 63     int k=logn[dfn[b]-dfn[a]+1];
 64     return d[a]+d[b]-(min(st[dfn[a]][k],st[dfn[b]-bin[k]+1][k])<<1);
 65 }
 66 struct node{
 67     int val;ll sz[3];
 68     node(int a=0,ll b=0,ll c=0,ll d=0){val=a,sz[0]=b,sz[1]=c,sz[2]=d;}
 69     inline bool operator <(const node &b)const
 70     {return val<b.val;}
 71 };
 72 vector<node> sta[N];
 73 void dfs3(int u,int f,int rt){
 74     sta[rt].push_back(node(val[u],1,dis(u,rt),fa[rt]?dis(u,fa[rt]):0));
 75     for(int i=head[u];i;i=Next[i]){
 76         int v=ver[i];
 77         if(v==f||vis[v]) continue;
 78         dfs3(v,u,rt);
 79     }
 80 }
 81 void dfs4(int u){
 82     vis[u]=true;
 83     dfs3(u,0,u);sta[u].push_back(node(-1,0,0,0));
 84     sort(sta[u].begin(),sta[u].end());
 85     for(int i=0,j=sta[u].size();i<j-1;++i)
 86     sta[u][i+1].sz[0]+=sta[u][i].sz[0],
 87     sta[u][i+1].sz[1]+=sta[u][i].sz[1],
 88     sta[u][i+1].sz[2]+=sta[u][i].sz[2];
 89     for(int i=head[u];i;i=Next[i]){
 90         int v=ver[i];
 91         if(vis[v]) continue;
 92         rt=0,size=sz[v];
 93         dfs2(v,0),fa[rt]=u,dfs4(rt);
 94     }
 95 }
 96 inline node query(int id,int l,int r){
 97     if(id==0) return node();
 98     vector<node>::iterator it1=upper_bound(sta[id].begin(),sta[id].end(),node(r,0,0,0));--it1;
 99     vector<node>::iterator it2=upper_bound(sta[id].begin(),sta[id].end(),node(l-1,0,0,0));--it2;
100     return node(0,it1->sz[0]-it2->sz[0],it1->sz[1]-it2->sz[1],it1->sz[2]-it2->sz[2]);
101 }
102 inline ll calc(int u,int l,int r){
103     ll res=0;
104     for(int p=u;p;p=fa[p]){
105         node a=query(p,l,r);
106         res+=a.sz[1];
107         if(p!=u) res+=a.sz[0]*dis(p,u);
108         if(fa[p]) res-=a.sz[2]+a.sz[0]*dis(fa[p],u);
109     }
110     return res;
111 }
112 int main(){
113     ll ans=0;
114     n=read(),q=read(),maxn=read();
115     bin[0]=1,logn[0]=-1;
116     for(int i=1;i<=20;++i) bin[i]=bin[i-1]<<1;
117     while(bin[tp+1]<=(n<<1)) ++tp;
118     for(int i=1;i<=(n<<1);++i) logn[i]=logn[i>>1]+1;
119     for(int i=1;i<=n;++i) val[i]=read();
120     for(int i=1;i<n;++i){
121         int u=read(),v=read(),e=read();
122         add(u,v,e);
123     }
124     dfs1(1,0),ST();
125     rt=0,son[0]=n+1,size=n,dfs2(1,0);
126     dfs4(rt);
127     while(q--){
128         int a=read(),b=read(),c=read();
129         b=(b+ans)%maxn,c=(c+ans)%maxn;
130         if(b>c) b^=c^=b^=c;
131         print(ans=calc(a,b,c));
132     }
133     Ot();
134     return 0;
135 }
相關文章
相關標籤/搜索