1. 程式人生 > >bzoj4012 開店 樹鏈剖分&主席樹

bzoj4012 開店 樹鏈剖分&主席樹

       看題第一眼反應點分治。。。QAQ但是從來沒寫過動態點分治不會寫。

       然後扒到了一個樹鏈剖分的題解,發現還是可做的。

       考慮一個樸素的問題,如果沒有顏色限制,問所有點到u的距離之和是多少?

       兩點間距離dist(u,v)=deep(u)+deep(v)-2*deep(lca(u,v))。

       因此所有點到u的距離之和=deep(u)*n+Σ(i=1,n)deep(i)-2Σ(i=1,n)deep(lca(u,v))。

       因此關鍵就是求Σ(i=1,n)deep(lca(u,v))。

       換句話說,我們需要知道u的每一個祖先t是多少對(u,v)的lca,實際上又因為t是u的祖先,我們只需要知道t是多少個(v)的祖先,且v->t的路徑和u->t的路徑不重合。

       因此我們先暴力列舉每個點i,將i->rt的路徑覆蓋,送油i->rt的邊經過的次數+1。然後Σ(i=1,n)deep(lca(u,v))就是u->rt的路徑中,Σlen[e]*times[e],len[e]表示邊權,times[e]表示經過的次數。

       然後就可以用樹鏈剖分維護了。O((N+M)log^2N)。

       考慮顏色限制[l,r],將問題轉化為字首和統計[1,r]-[1,l-1]。

       然後我們根據顏色從小到大進行路徑覆蓋,由於每次只會修改O(log^2N)個點,用主席樹維護[1,i]的那顆線段樹。然後查詢的時候減一減就好了。時空複雜度O(Nlog^2N),似乎會MLE?沒關係因為樹鏈剖分好像是做不到log^2N的,只要把陣列稍微比Nlog^2N開小一點就好了。

AC程式碼如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define N 300005
#define M 20000005
using namespace std;

int n,m,mod,trtot,tot,dfsclk,fst[N],pnt[N],len[N],nxt[N];
int pos[N],son[N],fa[N],anc[N],ls[M],rs[M],cvr[M],sz[N],edg[N],rt[N];
ll sum[M],sumd[N],d[N],val[N];
struct node{ int x,y; }a[N];
int read(){
	int x=0; char ch=getchar();
	while (ch<'0' || ch>'9') ch=getchar();
	while (ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); }
	return x;
}
void add(int x,int y,int z){
	pnt[++tot]=y; len[tot]=z; nxt[tot]=fst[x]; fst[x]=tot;
}
bool cmp(node aa,node bb){ return aa.x<bb.x || aa.x==bb.x && aa.y<bb.y; }
void dfs(int x){
	sz[x]=1; int p;
	for (p=fst[x]; p; p=nxt[p]){
		int y=pnt[p]; if (fa[x]==y) continue;
		fa[y]=x; edg[y]=len[p]; d[y]=d[x]+len[p];
		dfs(y); sz[x]+=sz[y];
		if (sz[y]>sz[son[x]]) son[x]=y;
	}
}
void build(int x,int tp){
	pos[x]=++dfsclk; val[dfsclk]=edg[x]; anc[x]=tp;
	if (son[x]) build(son[x],tp); int p;
	for (p=fst[x]; p; p=nxt[p]){
		int y=pnt[p];
		if (fa[x]!=y && son[x]!=y) build(y,y);
	}
}
void ins(int l,int r,int x,int &y,int u,int v){
	y=++trtot; int mid=(l+r)>>1;
	sum[y]=sum[x]; cvr[y]=cvr[x];
	if (l==u && r==v){ ls[y]=ls[x]; rs[y]=rs[x]; cvr[y]++; return; }
	sum[y]+=val[v]-val[u-1];
	if (v<=mid){ rs[y]=rs[x]; ins(l,mid,ls[x],ls[y],u,v); }
	else if (u>mid){ ls[y]=ls[x]; ins(mid+1,r,rs[x],rs[y],u,v); }
	else{ ins(l,mid,ls[x],ls[y],u,mid); ins(mid+1,r,rs[x],rs[y],mid+1,v); }
}
ll qry(int l,int r,int k,int u,int v){
	ll t=(ll)(val[v]-val[u-1])*cvr[k];
	if (l==u && r==v) return t+sum[k];
	int mid=(l+r)>>1;
	if (v<=mid) return t+qry(l,mid,ls[k],u,v);
	else if (u>mid) return t+qry(mid+1,r,rs[k],u,v);
		else return t+qry(l,mid,ls[k],u,mid)+qry(mid+1,r,rs[k],mid+1,v);
}
int find(int x){
	int l=0,r=n+1,mid;
	while (l+1<r){
		mid=(l+r)>>1;
		if (a[mid].x<=x) l=mid; else r=mid;
	}
	return l;
}
int main(){
	n=read(); m=read(); mod=read(); int i;
	for (i=1; i<=n; i++){
		a[i].x=read(); a[i].y=i;
	}
	sort(a+1,a+n+1,cmp);
	for (i=1; i<n; i++){
		int x=read(),y=read(),z=read();
		add(x,y,z); add(y,x,z);
	}
	dfs(1); build(1,1);
	for (i=1; i<=n; i++){
		val[i]+=val[i-1]; sumd[i]=sumd[i-1]+d[a[i].y];
	}
	for (i=1; i<=n; i++){
		int x=a[i].y; rt[i]=rt[i-1];
		for (; x; x=fa[anc[x]])
			ins(1,n,rt[i],rt[i],pos[anc[x]],pos[x]);
	}
	ll ans=0; int k,x,y;
	while (m--){
		k=read(); x=(ans+read())%mod; y=(ans+read())%mod;
		if (x>y) swap(x,y);
		x=find(x-1); y=find(y);
		ans=d[k]*(y-x)+sumd[y]-sumd[x];
		for (; k; k=fa[anc[k]])
			ans-=(qry(1,n,rt[y],pos[anc[k]],pos[k])-qry(1,n,rt[x],pos[anc[k]],pos[k]))<<1;
		printf("%lld\n",ans);
	}
	return 0;
}


by lych

2016.2.29

相關推薦

bzoj4012 &主席

       看題第一眼反應點分治。。。QAQ但是從來沒寫過動態點分治不會寫。        然後扒到了一個樹鏈剖分的題解,發現還是可做的。        考慮一個樸素的問題,如果沒有顏色限制,問所有點到u的距離之和是多少?        兩點間距離dist(u,v)=de

bzoj 4012: [HNOI2015]+主席

題目描述 傳送門 題解 這道題維護和求解的方法和bzoj 3924: [Zjoi2015]幻想鄉戰略遊戲是類似的。 但是這道題有一個[L,R]的區間限制,所以我們用主席樹來維護,外層是按照離散化後的xi從小到大,內層是dfs序。 程式碼 #i

bzoj2588 -- +主席

stat dfs strong pri 權值線段樹 iostream top pan splay 先將權值離散。 顯然可以對於每個結點建一棵權值線段樹存這個點到根結點的路徑上的點權,詢問時在線段樹上二分,但這樣時間是O(n2log2n)的。 然後想到用主席樹優化,時間復雜度

hdu 6162 Ch’s gift(+主席)

spl memset show pen 路徑 esp ems href lan 題目鏈接:hdu 6162 Ch’s gift 題意: 給你一棵樹,樹上每個點有一個權值,現在有m個詢問,每次詢問給你一個s,t,L,R,問你從s到t的路徑上,權值在[L,R]內的總和為多少。

[GDOI2016][+主席]瘋狂動物城

題面: Description Nick 是隻在動物城以坑蒙拐騙為生的狐狸,兒時受到偏見的傷害,放棄了自己的理想。他被兔子 Judy 設下圈套,被迫與她合作查案,而捲入意想不到的陰謀,歷盡艱險後成為搭檔。他們識破了綿羊副市長 Bellwether 的計劃

Gym - 101848C Object-Oriented Programming (+線段+動態點)

C. Object-Oriented Programming time limit per test 3.0 s memory limit per test 1024 MB input standard in

【bzoj2836】魔法 +線段

urn fin pan online char font -s class efi 題目描述 輸入 輸出 樣例輸入 4 0 1 1 2 2 3 4 Add 1 3 1 Query 0 Query 1 Query 2 樣例輸出

[bzoj 2243]: [SDOI2011]染色 [][線段]

節點 query ext tran pac led str 包含 sans Description 給定一棵有n個節點的無根樹和m個操作,操作有2類: 1、將節點a到節點b路徑上所有點都染成顏色c; 2、詢問節點a到節點b路徑上的顏色段數量(連續相同顏色被認為是同

BZOJ2243 [SDOI2011]染色(+線段合並)

ech sca 註意 get printf truct bre sum lca 題目鏈接 BZOJ2243 樹鏈剖分+線段樹合並 線段樹合並的一些細節需要註意一下 #include <bits/stdc++.h> using namespace std;

【BZOJ1969】[Ahoi2005]LANE 航線規劃 離線++線段

個數 wap 鎖定 樹邊 mes zoj swap 相同 swa 【BZOJ1969】[Ahoi2005]LANE 航線規劃 Description 對Samuel星球的探險已經取得了非常巨大的成就,於是科學家們將目光投向了Samuel星球所在的星系—&md

BZOJ 2157 旅遊(+線段

ace 路徑 pan geo blog return amp min target 【題目鏈接】 http://www.lydsy.com/JudgeOnline/problem.php?id=2157 【題目大意】   支持修改邊,鏈上查詢最大值最小值總和

hdu3966 +線段 裸題

ont ret algo string map fine eof inf 初始化 HDU - 3966 題意:給一顆樹,3種操作,Q u 查詢u節點的權值,I a b c 對a到b的路徑上每個點的點權增加c,D a b c 對a b 路徑上所有點的點權減少c 思路:樹鏈剖

【BZOJ4811】[Ynoi2017]由乃的OJ +線段

size 數值 sin 分數 strong str blank cstring else 【BZOJ4811】[Ynoi2017]由乃的OJ Description 由乃正在做她的OJ。現在她在處理OJ上的用戶排名問題。OJ上註冊了n個用戶,編號為1~",一開始他們

HDU-3966 Aragorn's Story(+線段)

real letter 們的 等等 then 需要 family sea inpu Aragorn‘s Story Time Limit: 10000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Ot

【BZOJ4127】Abs +線段

include modify 題目 etc soft upd clu set mem 【BZOJ4127】Abs Description 給定一棵樹,設計數據結構支持以下操作 1 u v d  表示將路徑 (u,v) 加d 2 u v

HDU 5893 List wants to travel(+線段

color top ons set 基本 brush [0 pri cto 題目鏈接 HDU5893 2016年ICPC沈陽網絡賽的B題。這道題其和 BZOJ2243 基本一樣 那道題我也寫了題解 點這裏 兩道題的區別就是BZOJ這題是點的權值,這道題是邊權。 所以

【bzoj2238】Mst 最小生成樹++線段

生成樹 brush 輸出 兩個 下一條 整數 algorithm ted sin 題目描述 給出一個N個點M條邊的無向帶權圖,以及Q個詢問,每次詢問在圖中刪掉一條邊後圖的最小生成樹。(各詢問間獨立,每次詢問不對之後的詢問產生影響,即被刪掉的邊在下一條詢問中依然存在) 輸

BZOJ2157: 旅遊 線段

const ostream one size con head log alt 一行 http://www.lydsy.com/JudgeOnline/problem.php?id=2157 在對樹中數據進行改動的時候需要很多pushdown(具體操作見代碼),不然會w

BZOJ 4034: [HAOI2015]樹上操作 線段

|| 線段 top www. img 復習 如果 ext hide http://www.lydsy.com/JudgeOnline/problem.php?id=4034 算是對線段樹的一個復習,樹鏈剖分+區間增減單點增減區間查詢。真的簡單到不用lca,但是線段樹又寫

【BZOJ3626】[LNOI2014]LCA 離線++線段

log 根路徑 iostream 根節點 2個 scrip har eof family 【BZOJ3626】[LNOI2014]LCA Description 給出一個n個節點的有根樹(編號為0到n-1,根節點為0)。一個點的深度定義為這個節點到根的距離+1。設d