題目描述
Jiajia和Wind是一對恩愛的夫妻,而且他們有不少孩子。某天,Jiajia、Wind和孩子們決定在家裏玩捉迷藏遊戲。他們的家很大且構造很奇特,由N個屋子和N-1條雙向走廊組成,這N-1條走廊的分佈使得任意兩個屋子都互相可達。
遊戲是這樣進行的,孩子們負責躲藏,Jiajia負責找,而Wind負責操縱這N個屋子的燈。在起初的時候,全部的燈都沒有被打開。每一次,孩子們只會躲藏在沒有開燈的房間中,可是爲了增長刺激性,孩子們會要求打開某個房間的電燈或者關閉某個房間的電燈。爲了評估某一次遊戲的複雜性,Jiajia但願知道可能的最遠的兩個孩子的距離(即最遠的兩個關燈房間的距離)。
咱們將以以下形式定義每一種操做:
- C(hange) i 改變第i個房間的照明狀態,若原來打開,則關閉;若原來關閉,則打開。
- G(ame) 開始一次遊戲,查詢最遠的兩個關燈房間的距離。
輸入輸出格式
輸入格式:
第一行包含一個整數N,表示房間的個數,房間將被編號爲1,2,3…N的整數。
接下來N-1行每行兩個整數a, b,表示房間a與房間b之間有一條走廊相連。
接下來一行包含一個整數Q,表示操做次數。接着Q行,每行一個操做,如上文所示。
輸出格式:
對於每個操做Game,輸出一個非負整數到hide.out,表示最遠的兩個關燈房間的距離。若只有一個房間是關着燈的,輸出0;若全部房間的燈都開着,輸出-1。
輸入輸出樣例
說明
對於20%的數據, N ≤50, M ≤100;
對於60%的數據, N ≤3000, M ≤10000; 對於100%的數據, N ≤100000, M ≤500000。
動態點分治的板子題
(然而我該說我當初作這道題是抄了島娘和hzwer的括號序列麼……由於看着以爲代碼比較好抄……因此根本沒打過動態點分的板子……)
我就直接說一下思路(而後隨便放個別的大佬的代碼好了)
咱們考慮一下,在每個點須要維護這一個點在點分樹中往下延伸到黑點的全部長度,而後每一次都把最長的和次長的給鏈接起來
這個能夠每個節點開一個大根堆
然而若是兩條鏈是來自同一棵子樹的就GG了……
那麼能夠再開一個堆,維護這一個點的全部兒子的堆頂,而後每一次取出的最長和次長能夠保證不是在同一棵子樹裏
而後再開一個堆維護一下每個節點的答案……
考慮修改怎麼操做?每一次在第一個堆裏進行修改,維護第二個堆和第三個堆就能夠了
分治樹深度$logn$,堆操做時間複雜度是$logn$,總時間複雜度是$O(nlog^2n)$
而後放一下LadyLex大佬的代碼吧(纔不是由於我懶得打呢)
1 #include <cstdio> 2 #include <cstring> 3 #include <ctime> 4 #include <set> 5 #include <queue> 6 using namespace std; 7 #define N 100010 8 #define inf 0x3fffffff 9 #define Vt Vater[rt] 10 int n,e,adj[N]; 11 struct edge{int zhong,next;}s[N<<1]; 12 inline void add(int qi,int zhong) 13 {s[++e].zhong=zhong;s[e].next=adj[qi];adj[qi]=e;} 14 int Vater[N],size[N],root,totsize,maxs[N]; 15 bool state[N],vis[N]; 16 #define max(a,b) ((a)>(b)?(a):(b)) 17 #define min(a,b) ((a)<(b)?(a):(b)) 18 struct heap 19 { 20 priority_queue<int>q1,q2; 21 inline void push(int x){q1.push(x);} 22 inline void erase(int x){q2.push(x);} 23 inline int top() 24 { 25 while(q2.size()&&q1.top()==q2.top())q1.pop(),q2.pop(); 26 return q1.top(); 27 } 28 inline void pop() 29 { 30 while(q2.size()&&q1.top()==q2.top())q1.pop(),q2.pop(); 31 q1.pop(); 32 } 33 inline int top2() 34 { 35 int val=top();pop(); 36 int ret=top();push(val); 37 return ret; 38 } 39 inline int size() 40 { 41 return q1.size()-q2.size(); 42 } 43 }h1[N],h2[N],h3; 44 inline void dfs1(int rt,int fa) 45 { 46 size[rt]=1,maxs[rt]=0; 47 for(int i=adj[rt];i;i=s[i].next) 48 if(s[i].zhong!=fa&&!vis[s[i].zhong]) 49 dfs1(s[i].zhong,rt),size[rt]+=size[s[i].zhong], 50 maxs[rt]=max(maxs[rt],size[s[i].zhong]); 51 maxs[rt]=max(maxs[rt],totsize-maxs[rt]); 52 if(maxs[rt]<maxs[root])root=rt; 53 } 54 int f[N][18],bin[25],tp,deep[N]; 55 inline void pre(int rt,int fa) 56 { 57 f[rt][0]=fa;deep[rt]=deep[fa]+1; 58 for(int i=1;bin[i]+1<=deep[rt];++i)f[rt][i]=f[f[rt][i-1]][i-1]; 59 for(int i=adj[rt];i;i=s[i].next) 60 if(s[i].zhong!=fa)pre(s[i].zhong,rt); 61 } 62 inline int LCA(int a,int b) 63 { 64 if(deep[a]<deep[b])a^=b,b^=a,a^=b; 65 int i,cha=deep[a]-deep[b]; 66 for(i=tp;~i;--i)if(cha&bin[i])a=f[a][i]; 67 if(a==b)return a; 68 for(i=tp;~i;--i) 69 if(f[a][i]!=f[b][i])a=f[a][i],b=f[b][i]; 70 return f[a][0]; 71 } 72 inline int dis(int a,int b) 73 {return deep[a]+deep[b]-(deep[LCA(a,b)]<<1);} 74 inline void dfs3(int rt,int fa,int Vatty) 75 { 76 h1[root].push(dis(rt,Vatty)); 77 for(int i=adj[rt];i;i=s[i].next) 78 if(!vis[s[i].zhong]&&s[i].zhong!=fa) 79 dfs3(s[i].zhong,rt,Vatty); 80 } 81 inline void dfs2(int rt,int fa) 82 { 83 Vt=fa,vis[rt]=1,h2[rt].push(0); 84 int siz=totsize; 85 for(int i=adj[rt];i;i=s[i].next) 86 if(!vis[s[i].zhong]) 87 { 88 if(size[s[i].zhong]>size[rt]) 89 totsize=siz-size[rt]; 90 else 91 totsize=size[s[i].zhong]; 92 root=0,dfs1(s[i].zhong,0),dfs3(root,0,rt); 93 h2[rt].push(h1[root].top()),dfs2(root,rt); 94 } 95 if(h2[rt].size()>1)h3.push(h2[rt].top()+h2[rt].top2()); 96 } 97 inline void turnoff(int who) 98 { 99 int val,tmp; 100 if(h2[who].size()>1)h3.erase(h2[who].top()+h2[who].top2()); 101 h2[who].push(0); 102 if(h2[who].size()>1)h3.push(h2[who].top()+h2[who].top2()); 103 //queue empty() 後依然有數 104 for(int rt=who;Vt;rt=Vt) 105 { 106 if(h2[Vt].size()>1)h3.erase(h2[Vt].top()+h2[Vt].top2()); 107 if(h1[rt].size())h2[Vt].erase(h1[rt].top()); 108 h1[rt].push(dis(who,Vt)); 109 h2[Vt].push(h1[rt].top()); 110 if(h2[Vt].size()>1)h3.push(h2[Vt].top()+h2[Vt].top2()); 111 } 112 } 113 inline void turnon(int who) 114 { 115 int val,tmp; 116 if(h2[who].size()>1)h3.erase(h2[who].top()+h2[who].top2()); 117 h2[who].erase(0); 118 if(h2[who].size()>1)h3.push(h2[who].top()+h2[who].top2()); 119 //queue empty()後依然有數 120 for(int rt=who;Vt;rt=Vt) 121 { 122 if(h2[Vt].size()>1)h3.erase(h2[Vt].top()+h2[Vt].top2()); 123 h2[Vt].erase(h1[rt].top()); 124 h1[rt].erase(dis(who,Vt)); 125 if(h1[rt].size())h2[Vt].push(h1[rt].top()); 126 if(h2[Vt].size()>1)h3.push(h2[Vt].top()+h2[Vt].top2()); 127 } 128 } 129 char B[1<<15],X=0,*S=B,*T=B; 130 #define getc ( S==T&&( T=(S=B)+fread(B,1,1<<15,stdin),S==T )?0:*S++ ) 131 inline int read() 132 { 133 int x=0;while(X<'0'||X>'9')X=getc; 134 while(X>='0'&&X<='9')x=10*x+(X^48),X=getc; 135 return x; 136 } 137 inline void readc(){X=getc;while(X<'A'||X>'Z')X=getc;} 138 int main() 139 { 140 // freopen("hide1.in","r",stdin); 141 // freopen("hide.out","w",stdout); 142 n=read(); 143 register int i,j,q,a,b,cnt=n; 144 for(bin[0]=i=1;i<=20;++i)bin[i]=bin[i-1]<<1; 145 while(bin[tp+1]<=n)++tp; 146 for(i=1;i<n;++i) 147 a=read(),b=read(),add(a,b),add(b,a); 148 pre(1,0); 149 maxs[0]=inf,root=0,totsize=n,dfs1(1,0),dfs2(root,0); 150 q=read(); 151 while(q--) 152 { 153 readc(); 154 if(X=='C') 155 { 156 i=read(); 157 if(state[i])++cnt,turnoff(i); 158 else --cnt,turnon(i); 159 state[i]^=1; 160 } 161 else 162 { 163 if(cnt<2)printf("%d\n",cnt-1); 164 else printf("%d\n",h3.top()); 165 } 166 } 167 }
BZOJ 3924: [Zjoi2015]幻想鄉戰略遊戲(動態點分治)
題目描述
傲嬌少女幽香正在玩一個很是有趣的戰略類遊戲,原本這個遊戲的地圖其實還不算太大,幽香還能管得過來,可是不知道爲何如今的網遊廠商把遊戲的地圖越作越大,以致於幽香一眼根本看不過來,更別說和別人打仗了。
在打仗以前,幽香如今面臨一個很是基本的管理問題須要解決。 整個地圖是一個樹結構,一共有n塊空地,這些空地被n-1條帶權邊鏈接起來,使得每兩個點之間有一條惟一的路徑將它們鏈接起來。
在遊戲中,幽香可能在空地上增長或者減小一些軍隊。同時,幽香能夠在一個空地上放置一個補給站。 若是補給站在點u上,而且空地v上有dv個單位的軍隊,那麼幽香天天就要花費dv*dist(u,v)的金錢來補給這些軍隊。
因爲幽香須要補給全部的軍隊,所以幽香總共就要花費爲Sigma(Dv*dist(u,v),其中1<=V<=N)的代價。其中dist(u,v)表示u個v在樹上的距離(惟一路徑的權和)。
由於遊戲的規定,幽香只能選擇一個空地做爲補給站。在遊戲的過程當中,幽香可能會在某些空地上製造一些軍隊,也可能會減小某些空地上的軍隊,進行了這樣的操做之後,出於經濟上的考慮,幽香每每能夠移動他的補給站從而省一些錢。
可是因爲這個遊戲的地圖是在太大了,幽香沒法輕易的進行最優的安排,你能幫幫她嗎? 你能夠假定一開始全部空地上都沒有軍隊。
輸入輸出格式
輸入格式:
第一行兩個數n和Q分別表示樹的點數和幽香操做的個數,其中點從1到n標號。 接下來n-1行,每行三個正整數a,b,c,表示a和b之間有一條邊權爲c的邊。 接下來Q行,每行兩個數u,e,表示幽香在點u上放了e單位個軍隊(若是e<0,就至關因而幽香在u上減小了|e|單位個軍隊,說白了就是du←du+e)。數據保證任什麼時候刻每一個點上的軍隊數量都是非負的。
輸出格式:
對於幽香的每一個操做,輸出操做完成之後,天天的最小花費,也即若是幽香選擇最優的補給點進行補給時的花費。
輸入輸出樣例
10 5 1 2 1 2 3 1 2 4 1 1 5 1 2 6 1 2 7 1 5 8 1 7 9 1 1 10 1 3 1 2 1 8 1 3 1 4 1
0 1 4 5 6
說明
對於全部數據,1<=c<=1000, 0<=|e|<=1000, n<=10^5, Q<=10^5 很是神奇的是,對於全部數據,這棵樹上的點的度數都不超過20,且N,Q>=1
咱們具體來分析一下這道題目咱們要維護什麼
題目要求使$\sum d_v*dis(u,v)$最小,其中$d_v$爲$v$點的點權,$dis(u,v)$爲原樹中$u,v$兩點的距離。題目要求就是求帶權重心。假設咱們當前已經選定了點$v$爲答案,那麼考慮它的一個子節點$w$,若是把補給站從點$v$轉移到$w$,那麼$w$的全部子樹內的點到補給站的距離少了$dis(v,w)$,而其餘全部點到補給站的距離多了$dis(v,w)$。咱們假設$sum_v[v]$爲$v$的子樹內的點權和,那麼答案總共的變化量是$$dis(u,v)*(sum_v[v]-sum_v[w]-sum_v[w])$$
不難發現,當$sum_v[w]*2>sum_v[v]$的時候,答案的變化量是小於零的,也就是說代價減少,能夠變得更優。並且,知足這樣條件的點$w$最多隻有一個
那麼咱們能夠每一次選定一個點,而後看看往他的哪一個子樹走更優,若是沒有說明他本身就已是最優的了。這樣不斷下去確定能找到答案。
可是因爲原圖多是一條鏈,要怎麼作才能保證複雜度呢?咱們選擇在點分樹上走,每一次都跳到它下一層的重心,這樣能夠保證層數最多隻有$O(log n)$
而後考慮如何維護答案。不難發現,對於點分樹上一個點$v$,它的子樹就是在點分治時它被選爲重心時的那棵樹。考慮點分樹上的一對父子$u,v$,咱們設$sum_a[v]$表示$v$的子樹內的全部點到他的代價之和,$sum_b[v]$爲$v$的子樹內的全部點到$v$點父親(也就是點$u$)的距離之和,$sum_v[v]$仍是表示子樹的點權之和。那麼咱們設答案已經選定爲點$w$,而且已經把$v$這一整棵子樹上全部點到點$w$的距離之和計算完畢,那麼考慮要加上$v$在點分樹上的父親$u$,要計算的答案只有$u$的不包含$v$的子樹,答案是$sum_a[v]+sum_a[u]-sum_b[v]+sum_v[u]*dis(u,v)$。因而只要在點分樹上不斷找父親併合並,就能夠知道答案了
而後咱們只要能在修改時維護好這三個數組就能夠了
至於修改時如何維護呢?咱們修改一個點以後,而後不斷在點分樹上往父節點跳,每一次只會對它的祖先節點的這些值產生影響,一個一個修改便可
ps:還有個小細節,由於咱們判斷是否更優要在原樹上走,而後計算答案要在點分樹裏走,因此對於每個節點不只要記錄它的父親,還要記錄它往下能走哪幾條邊,在原樹的邊判斷是否更優,而後往點分樹上走來保證計算答案的複雜度
而後又新學會了一招,用$RMQ O(1)$查詢$LCA$(只會倍增和樹剖的我瑟瑟發抖),總時間複雜度$O(nlog^2n)$
1 //minamoto 2 #include<cstdio> 3 #include<iostream> 4 #include<cstring> 5 #define ll long long 6 #define N 100005 7 #define inf 0x3f3f3f3f 8 #define rint register int 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 struct G{ 31 int head[N],Next[N<<1],edge[N<<1],ver[N<<1],tot; 32 G(){tot=0;memset(head,0,sizeof(head));} 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 } 36 }T1,T2; 37 int n,q,st[N<<1][18],logn[N<<1],bin[25],tp; 38 ll sum,ans,d[N],dis1[N],dis2[N],sumv[N]; 39 int dfn[N],num; 40 void dfs1(int u,int fa){ 41 st[dfn[u]=++num][0]=d[u]; 42 for(int i=T1.head[u];i;i=T1.Next[i]){ 43 int v=T1.ver[i]; 44 if(v==fa) continue; 45 d[v]=d[u]+T1.edge[i],dfs1(v,u),st[++num][0]=d[u]; 46 } 47 } 48 inline ll LCA(int a,int b){ 49 if(dfn[a]>dfn[b]) a^=b^=a^=b; 50 int k=logn[dfn[b]-dfn[a]+1]; 51 return min(st[dfn[a]][k],st[dfn[b]-bin[k]+1][k])<<1; 52 } 53 inline ll dis(int a,int b){return d[a]+d[b]-LCA(a,b);} 54 int sz[N],son[N],size,rt,fa[N];bool vis[N]; 55 void dfs2(int u,int fa){ 56 sz[u]=1,son[u]=0; 57 for(int i=T1.head[u];i;i=T1.Next[i]){ 58 int v=T1.ver[i]; 59 if(vis[v]||v==fa) continue; 60 dfs2(v,u),sz[u]+=sz[v],cmax(son[u],sz[v]); 61 } 62 cmax(son[u],size-sz[u]); 63 if(son[u]<son[rt]) rt=u; 64 } 65 void dfs3(int u){ 66 vis[u]=true; 67 for(int i=T1.head[u];i;i=T1.Next[i]){ 68 int v=T1.ver[i]; 69 if(vis[v]) continue; 70 rt=0,size=sz[v],son[0]=n+1; 71 dfs2(v,0),T2.add(u,rt,v),fa[rt]=u,dfs3(rt); 72 } 73 } 74 inline void update(int u,int val){ 75 sumv[u]+=val; 76 for(int p=u;fa[p];p=fa[p]){ 77 ll dist=dis(fa[p],u)*val; 78 dis1[fa[p]]+=dist; 79 dis2[p]+=dist; 80 sumv[fa[p]]+=val; 81 } 82 } 83 inline ll calc(int u){ 84 ll ans=dis1[u]; 85 for(int p=u;fa[p];p=fa[p]){ 86 ll dist=dis(fa[p],u); 87 ans+=dis1[fa[p]]-dis2[p]; 88 ans+=dist*(sumv[fa[p]]-sumv[p]); 89 } 90 return ans; 91 } 92 ll query(int u){ 93 ll ans=calc(u); 94 for(int i=T2.head[u];i;i=T2.Next[i]){ 95 ll tmp=calc(T2.edge[i]); 96 if(tmp<ans) return query(T2.ver[i]); 97 } 98 return ans; 99 } 100 void init(){ 101 n=read(),q=read(); 102 bin[0]=1,logn[0]=-1; 103 for(rint i=1;i<=20;++i) bin[i]=bin[i-1]<<1; 104 while(bin[tp+1]<=(n<<1)) ++tp; 105 for(rint i=1;i<=(n<<1);++i) logn[i]=logn[i>>1]+1; 106 for(rint i=1;i<n;++i){ 107 rint u=read(),v=read(),e=read(); 108 T1.add(u,v,e),T1.add(v,u,e); 109 } 110 dfs1(1,0),rt=0,son[0]=n+1,size=n,dfs2(1,0); 111 for(rint j=1;j<=tp;++j) 112 for(rint i=1;i+bin[j]-1<=(n<<1);++i) 113 st[i][j]=min(st[i][j-1],st[i+bin[j-1]][j-1]); 114 } 115 int main(){ 116 init(); 117 int LastOrder=rt;dfs3(rt); 118 while(q--){ 119 int x=read(),y=read();update(x,y); 120 print(query(LastOrder)); 121 } 122 Ot(); 123 return 0; 124 }
BZOJ4012 [HNOI2015]開店 (動態點分治)
Description
風見幽香有一個好朋友叫八雲紫,她們常常一塊兒看星星看月亮從詩詞歌賦談到
Input
第一行三個用空格分開的數 n、Q和A,表示樹的大小、開店的方案個數和妖
Output
對於每一個方案,輸出一行表示方便值。
Sample Input
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
957
7161
9466
3232
5223
1879
1669
1282
0
HINT
知足 n<=150000,Q<=200000。對於全部數據,知足 A<=10^9
咱們考慮對於每個點分樹上的點維護什麼。咱們記錄三個值,$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$,並不斷往上跳並維護答案就能夠了。
然而上面只是爲了方便理解,由於具體的計算不是這樣的。咱們對於$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]$(由於實際上存儲時不可能按年齡,因此能夠在每個點開一個vector而後排序一下便可)
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 }
emm……最後再來兩個大boss吧(我已經想(抄)到了一種很棒的解法惋惜這裏寫不下)
說真的抄代碼其實很累的
洛谷P3676 小清新數據結構題--------->蒟蒻的題解
bzoj3435 [Wc2014]紫荊花之戀(權限)(非權限)---------------->蒟蒻的題解
那麼就到這裏吧……感謝觀看……累死我了……