【BZOJ】3052: [wc2013]糖果公园

http://www.lydsy.com/JudgeOnline/problem.php?id=3052

题意:n个带颜色的点(m种),q次询问,每次询问x到y的路径上sum{w[次数]*v[颜色]},可以单点修改颜色。(n, m, q<=100000)

#include <bits/stdc++.h>
using namespace std;
const int N=100005, M=100005;
typedef long long ll;
inline int getint() { int x=0; char c=getchar(); while(c<‘0‘||c>‘9‘) c=getchar(); while(c>=‘0‘&&c<=‘9‘) (x*=10)+=c-‘0‘, c=getchar(); return x; }
inline void print(ll a) { if(!a) return; print(a/10); putchar(‘0‘+(a%10));}
int ihead[N], cnt, blo[N<<1], f[N][17], FF[N], LL[N], tot, dep[N], cal[N], pos[N<<1], col[M], n, m, W[N], V[M], qu, n_ask, n_tm, col_pre[N];
ll Ans[M], ans;
bool st[N];
struct E { int next, to; }e[N<<1];
struct Q { int x, y, lca, id, tm; }q[M];
struct T { int x, y, last; }Time[M];
inline bool cmp(const Q &a, const Q &b) { return blo[a.x]==blo[b.x]?(blo[a.y]==blo[b.y]?a.tm<b.tm:blo[a.y]<blo[b.y]):blo[a.x]<blo[b.x]; }
inline void add(int x, int y) { e[++cnt]=(E){ihead[x], y}; ihead[x]=cnt; e[++cnt]=(E){ihead[y], x}; ihead[y]=cnt; }
void dfs(int x) {
	pos[FF[x]=++tot]=x;
	for(int i=1; i<=16; ++i) f[x][i]=f[f[x][i-1]][i-1];
	for(int i=ihead[x]; i; i=e[i].next) if(e[i].to!=f[x][0])
		dep[e[i].to]=dep[x]+1, f[e[i].to][0]=x, dfs(e[i].to);
	pos[LL[x]=++tot]=x;
}
inline int LCA(int x, int y) {
	if(dep[x]<dep[y]) swap(x, y);
	int d=dep[x]-dep[y];
	for(int i=16; i>=0; --i) if((d>>i)&1) x=f[x][i]; if(x==y) return x;
	for(int i=16; i>=0; --i) if(f[x][i]!=f[y][i]) x=f[x][i], y=f[y][i];
	return f[x][0];
}
inline void update(int x) {
	if(st[x]) { ans-=(ll)V[col[x]]*W[cal[col[x]]]; --cal[col[x]]; }
	else { ++cal[col[x]]; ans+=(ll)V[col[x]]*W[cal[col[x]]];  }
	st[x]=!st[x];
}
inline void change(int a, int b) {
	if(st[a]) { update(a); col[a]=b; update(a); }
	else col[a]=b;
}
inline void timechange(int &now, int goal) {
	while(now<goal) ++now, change(Time[now].x, Time[now].y);
	while(now>goal) change(Time[now].x, Time[now].last), --now;
}
void work() {
	int l=1, r=0, now=0, nl, nr;
	sort(q+1, q+1+n_ask, cmp);
	for(int i=1; i<=n_ask; ++i) {
		nl=q[i].x; nr=q[i].y;
		timechange(now, q[i].tm);
		while(l<nl) update(pos[l++]);
		while(l>nl) update(pos[--l]);
		while(r<nr) update(pos[++r]);
		while(r>nr) update(pos[r--]);
		if(q[i].lca) update(q[i].lca);
		Ans[q[i].id]=ans;
		if(q[i].lca) update(q[i].lca);
	}
	while(r>=l) update(pos[r--]);
}
void pre() {
	dfs((n+1)>>1);
	int nn=n<<1, sq=pow(nn, 2.0/3)*0.5;
	for(int i=1; i<=nn; ++i) blo[i]=(i-1)/sq;
	for(int i=1; i<=qu; ++i) {
		int type=getint(), x=getint(), y=getint();
		if(!type) {
			++n_tm;
			Time[n_tm]=(T){x, y, col_pre[x]}; col_pre[x]=y;
			continue;
		}
		++n_ask;
		if(FF[x]>FF[y]) swap(x, y);
		int lca=LCA(x, y);
		if(lca==x) 	q[n_ask]=(Q){FF[x], FF[y], 0, n_ask, n_tm};
		else 		q[n_ask]=(Q){LL[x], FF[y], lca, n_ask, n_tm};
	}
}
int main() {
	n=getint(); m=getint(); qu=getint();
	for(int i=1; i<=m; ++i) V[i]=getint();
	for(int i=1; i<=n; ++i) W[i]=getint();
	for(int i=1; i<n; ++i) {
		int x=getint(), y=getint();
		add(x, y);
	}
	for(int i=1; i<=n; ++i) col[i]=col_pre[i]=getint();
	pre();
	work();
	for(int i=1; i<=n_ask; ++i) print(Ans[i]), puts("");
	return 0;
}

  

一开始我直接在每个修改之间计算答案= =然后果断T了= =QAQ

膜拜vfk.....

首先分块是三元分块!并且要进行修改的操作以及逆操作(最坏变成O(n)辣= =)

第三元就是询问的时间。

然后写完后发现还是好慢QAQ

因为我把块大小就是分成了O(n^0.5)QAQ

继续膜拜vfk

发现要分块成O(n^(2/3)).....则有O(n^(1/3))个块...然后具体证明请看 http://vfleaking.blog.163.com/blog/static/174807634201311011201627/

艾雨青大神犇教导我们,将树分块!

如前所述的分块方法。当时艾雨青神犇讲题的时候的分块方法没听清 T_T,上面的分块方法是我自己YY出来的。

取B = n ^ (2 / 3),设 nBlo为块的个数,用bloNum[v]来代表v所在块的编号。(block number)

则同一个块内任意两结点的距离为O(n ^ (2 / 3))的。

按照之前我说的方式对询问进行排序,按顺序作答。

注意到(bloNum[curV], bloNum[curU])一共有nBlo ^ 2个取值。

那么如果移动一次,curV还在原来的块,curU还在原来的块,这种移动的总时间复杂度是O(nBlo ^ 2 * q)的。(因为curTi还要移动)

如果移动一次,curV不在原来的块,curU不在原来的块,这种移动发生的次数最多为 nBlo ^ 2。因为我是排好序的了嘛,相同块的是放在一起的。而这种移动发生一次最坏是O(n + n + q) = O(n)。(n、q是同阶的)

所以这样回答所有询问,时间复杂度就是O(nBlo ^ 2 * n)的。

由于B = n ^ (2 / 3),块的大小介于[B, 3 * B]之间。

则nBlo = O(n ^ (1 / 3))

则时间复杂度为O(n ^ (5 / 3))。

(如果不会dfs序的话请看我上一篇博文【BZOJ】3757: 苹果树

时间: 2024-10-12 13:41:58

【BZOJ】3052: [wc2013]糖果公园的相关文章

bzoj 3052: [wc2013]糖果公园(带修改的树上莫队)

3052: [wc2013]糖果公园 Time Limit: 200 Sec  Memory Limit: 512 MB Submit: 892  Solved: 425 [Submit][Status][Discuss] Description Input Output Sample Input Sample Input Sample Output 84 131 27 84 HINT Source [Submit][Status][Discuss] 题解:bzoj 2120 和 bzoj 37

[bzoj 3052][wc2013]糖果公园

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3052 [wc2013]糖果公园 Time Limit: 200 Sec  Memory Limit: 512 MBSubmit: 1213  Solved: 609[Submit][Status][Discuss] Description Input Output Sample Input Sample Input Sample Output 84 131 27 84 树上莫队,把树分块,

bzoj 3052: [wc2013]糖果公园 带修改莫队

3052: [wc2013]糖果公园 Time Limit: 250 Sec  Memory Limit: 512 MBSubmit: 506  Solved: 189[Submit][Status] Description Input Output Sample Input Sample Input Sample Output 84 131 27 84 HINT 本来这道题想到了莫队算法,但是看到带修改就直接放弃了.结果看题解才发现带修改居然也能用莫队!!!之所以可以这样用,是因为修改的时间复

[BZOJ 3052] [wc2013] 糖果公园 【树上莫队】

题目链接:BZOJ - 3052 题目分析 这道题就是非常经典的树上莫队了,并且是带修改的莫队. 带修改的莫队:将询问按照 左端点所在的块编号为第一关键字,右端点所在的块为第二关键字,位于第几次修改之后为第三关键字 排序. 我们将块的大小设置在 n^(2/3) ,这样一共有 n^(1/3) 个块.最后算法的总复杂度会是 n^(5/3) . 每一次如何从上一个询问转移来呢? 假设上一个询问是 (lx, ly, lt) ,这次的询问是 (x, y, t) .t 代表是在第 t 次修改操作之后. 首先

BZOJ 3052 [wc2013]糖果公园 树上莫队

题意:链接 方法:莫队上树 解析: 首先先考虑个莫队的算法,树分块 然后怎么做呢? 可以设两个指针么,然后按一定的排序方式移动指针,使复杂度可过. 观察到这道题是100s的,n^2是GG的,但比n^2稍微小一点就不GG了, 所以排序的作用就体现了. 按照左端点所在块为第一关键字,右端点所在块为第二关键字出现时间为第三关键字排序. 一共有n的1/3次方个块,所以所有的询问的左右端点所在的块的取值最多之后n的2/3次方种,对于每一种,对时间的修改最多会从尾改到头,所以又多乘一个q,n,q同阶,所以总

BZOJ 3052 WC2013 糖果公园 带修改树上莫队

题目大意:给定一棵树,每个点有一个颜色,提供两种操作: 1.询问两点间路径上的Σv[a[i]]*w[k],其中a[i]代表这个点的颜色,k表示这个点是这种颜色第k次出现 2.修改某个点的颜色 VfleaKing的题解见 http://vfleaking.blog.163.com/blog/static/174807634201311011201627/ 带修改莫队上树--如果不带修改就正常搞就好了 如果带修改的话,令块的大小为n^(2/3) 将询问排序时第一键值为左端点所在块,第二键值为右端点所

【BZOJ】3052: [wc2013]糖果公园 树分块+待修改莫队算法

[题目]#58. [WC2013]糖果公园 [题意]给定n个点的树,m种糖果,每个点有糖果ci.给定n个数wi和m个数vi,第i颗糖果第j次品尝的价值是v(i)*w(j).q次询问一条链上每个点价值的和或修改一个点的糖果ci.n,m,q<=10^5. [算法]树分块+带修改莫队算法 [题解]参考:WC 2013 糖果公园 park 题解 by vfleaking 首先树分块,参考王室联邦的方法.确定块大小为B,一遍DFS可以分成若干大小为[B,3B]的块,性质是块内两点距离至多为B. 定义(x,

WC2013 糖果公园

COGS 1817. [WC2013]糖果公园 http://www.cogs.pro/cogs/problem/problem.php?pid=1817 ★★★☆   输入文件:park.in   输出文件:park.out   简单对比时间限制:8 s   内存限制:512 MB [题目描述] Candyland 有一座糖果公园,公园里不仅有美丽的风景.好玩的游乐项目,还有许多免费糖果的发放点,这引来了许多贪吃的小朋友来糖果公园玩. 糖果公园的结构十分奇特,它由 n 个游览点构成,每个游览点

AC日记——[WC2013]糖果公园 cogs 1817

[WC2013]糖果公园 思路: 带修改树上莫队(模板): 来,上代码: #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define maxn 100005 #define ll long long struct QueryType { ll u,v,t,id;