zoukankan      html  css  js  c++  java
  • 【luogu P4074】【ybt金牌导航6-4-3】糖果公园(带修莫队)(树上莫队)

    糖果公园

    题目链接:luogu P4074 / ybt金牌导航6-4-3

    题目大意

    给你一棵树,树上点有颜色,颜色有权值,然后还给出新鲜度。
    然后有一些操作,可能是修改一个点的颜色,可能是给你一条路径,问你路径的分数。
    路径的分数是按顺序经过点,每个点给分数的贡献是它颜色的权值乘上新鲜度的第 i 项(i 是你第几次经到这个颜色的点)。
    询问之间独立。

    思路

    这道题其实就是模板的带修树上莫队题。

    首先就是如何分块,我们考虑用这样的一种分块方式:
    我们每遍历处理完一个点的子树,就把这个点放入队列中。然后如果当前这个点的儿子要处理的点数超过了大小,就把那些找出来标成一类。

    然后接着有时间就是 (n^{frac{2}{3}}) 块长,然后就是正常的搞搞待修莫队。
    然后你会发现询问的修改好像不知道要怎么移动?

    然后其实你通过观察会发现,我们莫队不是有一个点是否贡献吗,你会发现你原来是 ((x1,y1)),现在是 ((x2,y2)),我们其实就把 (x1)(x2)(y1)(y2) 这两个路径上的点状态取反即可。
    由于我们是莫队,那我们就可以暴力的移动修改。

    然后 ybt 要卡常,我卡了三页真的卡不动了。

    代码(这个ybt会只有70)

    //#pragma GCC optimize(2)
    
    #include<cmath>
    #include<cstdio>
    #include<algorithm>
    #define ll long long
    
    using namespace std;
    
    const int N = 100005;
    struct ask {
    	int t, x, y, num;
    }a[N];
    int pl[N], bef[N], to[N], num[N];
    int n, m, q, v[N], w[N], bn;
    int tim, qn, op, x, y, t;
    int c[N], lst[N], sz, bl[N], LCA;
    int deg[N], fa[N][18], sta[N];
    bool in[N];
    ll ans, an[N];
    
    struct node {
    	int to, nxt;
    }e[N << 1];
    int le[N], KK;
    
    inline void add(int x, int y) {
    	e[++KK] = (node){y, le[x]}; le[x] = KK;
    	e[++KK] = (node){x, le[y]}; le[y] = KK;
    }
    
    inline int read() {
    	int re = 0;
    	char c = getchar();
    	while (c < '0' || c > '9') c = getchar();
    	while (c >= '0' && c <= '9') {
    		re = (re << 3) + (re << 1) + c - '0';
    		c = getchar();
    	}
    	return re;
    }
    
    inline int dfs_bl(int now, int father) {//分块
    	fa[now][0] = father;
    	deg[now] = deg[father] + 1;
    	int sn = 0;
    	for (int i = le[now]; i; i = e[i].nxt)
    		if (e[i].to ^ father) {
    			sn += dfs_bl(e[i].to, now);
    			if (sn >= sz) {
    				bn++;
    				while (sn) {
    					bl[sta[sta[0]]] = bn;
    					sta[0]--; sn--;
    				}
    			}
    		}
    	sta[++sta[0]] = now; sn++;
    	return sn;
    }
    
    bool cmp(ask x, ask y) {//莫队排序
    	if (bl[x.x] ^ bl[y.x]) return bl[x.x] < bl[y.x];
    	if (bl[x.y] ^ bl[y.y]) return (bl[x.x] & 1) ? bl[x.y] < bl[y.y] : bl[x.y] > bl[y.y];
    	return ((bl[x.x] ^ bl[x.y]) & 1) ? x.t < y.t : x.t > y.t;
    }
    
    inline int lca(int x, int y) {
    	if (deg[y] > deg[x]) swap(x, y);
    	for (int i = 17; i >= 0; i--)
    		if (deg[fa[x][i]] >= deg[y]) x = fa[x][i];
    	if (x == y) return x;
    	for (int i = 17; i >= 0; i--)
    		if (fa[x][i] ^ fa[y][i]) x = fa[x][i], y = fa[y][i];
    	return fa[x][0];
    }
    
    inline void putans(int x) {//更新答案(一个点)
    	if (!in[x]) {
    		num[c[x]]++;
    		ans += 1ll * v[c[x]] * w[num[c[x]]];
    	}
    	else {
    		ans -= 1ll * v[c[x]] * w[num[c[x]]];
    		num[c[x]]--;
    	}
    	in[x] ^= 1;
    }
    
    void change(int x, int y) {//给树上点更颜色
    	if (!in[x]) c[x] = y;
    		else {
    			putans(x);
    			c[x] = y;
    			putans(x);
    		}
    }
    
    inline void turn(int x, int y) {//给树上路径上的所有点统计(LCA不会统计)
    	while (x ^ y) {
    		if (deg[x] > deg[y]) putans(x), x = fa[x][0];
    			else putans(y), y = fa[y][0];
    	}
    }
    
    inline void write(ll x) {
    	if (x > 9ll) write(x / 10);
    	putchar(x % 10 + '0');
    }
    
    int main() {
    	n = read(); m = read(); q = read();
    	for (int i = 1; i <= m; i++) v[i] = read();
    	for (int i = 1; i <= n; i++) w[i] = read();
    	for (int i = 1; i < n; i++) {
    		x = read(); y = read();
    		add(x, y);
    	}
    	for (int i = 1; i <= n; i++) c[i] = read(), lst[i] = c[i];
    	
    	for (int i = 1; i <= q; i++) {
    		op = read(); x = read(); y = read();
    		if (op == 0) {
    			tim++;
    			pl[tim] = x; bef[tim] = lst[x]; to[tim] = y;
    			lst[x] = y;
    		}
    		else {
    			a[++qn] = (ask){tim, x, y, qn};
    		}
    	}
    	
    	sz = pow(n, 2.0 / 3);
    	int tmp = dfs_bl(1, 0); if (tmp) bn++;
    	while (tmp) {
    		bl[sta[sta[0]]] = bn;
    		sta[0]--; tmp--;
    	}
    	for (int i = 1; i <= 17; i++)
    		for (int j = 1; j <= n; j++)
    			fa[j][i] = fa[fa[j][i - 1]][i - 1];
    	
    	sort(a + 1, a + qn + 1, cmp);
    	t = a[1].t;
    	for (int i = 1; i <= t; i++) change(pl[i], to[i]);
    	turn(a[1].x, a[1].y);
    	LCA = lca(a[1].x, a[1].y);
    	putans(LCA);
    	an[a[1].num] = ans;
    	putans(LCA);
    	for (int i = 2; i <= qn; i++) {//莫队
    		while (t < a[i].t) t++, change(pl[t], to[t]);
    		while (t > a[i].t) change(pl[t], bef[t]), t--;
    		turn(a[i].x, a[i - 1].x);
    		turn(a[i].y, a[i - 1].y);
    		LCA = lca(a[i].x, a[i].y);
    		putans(LCA);//前面没有处理到 LCA 所以要单独处理
    		an[a[i].num] = ans;
    		putans(LCA);
    	}
    	
    	for (int i = 1; i <= qn; i++) write(an[i]), putchar('
    ');
    	
    	return 0;
    }
    

    后记

    使用了新的树上莫队,用了欧拉序然后就过了。

    新代码

    #include<cmath>
    #include<cstdio>
    #include<algorithm>
    #define ll long long
    
    using namespace std;
    
    const int N = 100001;
    struct ask {
    	int t, x, y, num, lca;
    }a[N];
    int pl[N], bef[N], to[N], num[N];
    int n, m, q, v[N], w[N], bn, tmpn;
    int tim, qn, op, x, y, t, dfn[2 * N];
    int c[N], lst[N], sz, bl[2 * N], LCA;
    int deg[N], fa[N][18], st[N], ed[N];
    bool in[N];
    ll ans, an[N];
    
    struct node {
    	int to, nxt;
    }e[2 * N];
    int le[N], KK;
    
    inline void add(int x, int y) {
    	e[++KK] = (node){y, le[x]}; le[x] = KK;
    	e[++KK] = (node){x, le[y]}; le[y] = KK;
    }
    
    int re;
    char cc;
    inline int read() {
    	re = 0;
    	cc = getchar();
    	while (cc < '0' || cc > '9') cc = getchar();
    	while (cc >= '0' && cc <= '9') {
    		re = (re << 3) + (re << 1) + cc - '0';
    		cc = getchar();
    	}
    	return re;
    }
    
    inline void dfs_bl(int now, int father) {
    	dfn[++tmpn] = now;
    	st[now] = tmpn;
    	fa[now][0] = father;
    	deg[now] = deg[father] + 1;
    	for (int i = le[now]; i; i = e[i].nxt)
    		if (e[i].to ^ father) {
    			dfs_bl(e[i].to, now);
    		}
    	dfn[++tmpn] = now;
    	ed[now] = tmpn;
    }
    
    inline bool cmp(ask x, ask y) {
    //	if (bl[x.x] ^ bl[y.x]) return bl[x.x] < bl[y.x];
    //	if (bl[x.y] ^ bl[y.y]) return (bl[x.x] & 1) ? bl[x.y] < bl[y.y] : bl[x.y] > bl[y.y];
    //	return ((bl[x.x] ^ bl[x.y]) & 1) ? x.t < y.t : x.t > y.t;
    	if (bl[x.x] ^ bl[y.x]) return bl[x.x] < bl[y.x];
    	if (bl[x.y] ^ bl[y.y]) return bl[x.y] < bl[y.y];
    	return x.t < y.t;
    }
    
    inline int lca(int x, int y) {
    	if (deg[y] > deg[x]) swap(x, y);
    	for (int i = 17; i >= 0; i--)
    		if (deg[fa[x][i]] >= deg[y]) x = fa[x][i];
    	if (x == y) return x;
    	for (int i = 17; i >= 0; i--)
    		if (fa[x][i] ^ fa[y][i]) x = fa[x][i], y = fa[y][i];
    	return fa[x][0];
    }
    
    inline void putans(int x) {
    	if (!in[x]) {
    		num[c[x]]++;
    		ans += 1ll * v[c[x]] * w[num[c[x]]];
    	}
    	else {
    		ans -= 1ll * v[c[x]] * w[num[c[x]]];
    		num[c[x]]--;
    	}
    	in[x] ^= 1;
    }
    
    inline void change(int x, int y) {
    	if (!in[x]) c[x] = y;
    		else {
    			putans(x);
    			c[x] = y;
    			putans(x);
    		}
    }
    
    void write(ll x) {
    	if (x > 9ll) write(x / 10);
    	putchar(x % 10 + '0');
    }
    
    int main() {
    	n = read(); m = read(); q = read();
    	for (int i = 1; i <= m; i++) v[i] = read();
    	for (int i = 1; i <= n; i++) w[i] = read();
    	for (int i = 1; i < n; i++) {
    		x = read(); y = read();
    		add(x, y);
    	}
    	for (int i = 1; i <= n; i++) c[i] = read(), lst[i] = c[i];
    	
    	sz = pow(2 * n, 2.0 / 3);
    	dfs_bl(1, 0);
    	for (int i = 1; i <= 17; i++)
    		for (int j = 1; j <= n; j++)
    			fa[j][i] = fa[fa[j][i - 1]][i - 1];
    	for (int i = 1; i <= 2 * n; i++) bl[i] = (i - 1) / sz + 1;
    	
    	for (int i = 1; i <= q; i++) {
    		op = read(); x = read(); y = read();
    		if (op == 0) {
    			tim++;
    			pl[tim] = x; bef[tim] = lst[x]; to[tim] = y;
    			lst[x] = y;
    		}
    		else {
    			LCA = lca(x, y);
    			if (st[x] > st[y]) swap(x, y);
    			if (LCA == x) a[++qn] = (ask){tim, st[x], st[y], qn, 0};
    				else a[++qn] = (ask){tim, ed[x], st[y], qn, LCA};
    		}
    	}
    	
    	sort(a + 1, a + qn + 1, cmp);
    	x = 1; y = 0; t = 0;
    	for (int i = 1; i <= qn; i++) {
    		while (t < a[i].t) t++, change(pl[t], to[t]);
    		while (t > a[i].t) change(pl[t], bef[t]), t--;
    		while (x < a[i].x) putans(dfn[x]), x++;
    		while (x > a[i].x) x--, putans(dfn[x]);
    		while (y < a[i].y) y++, putans(dfn[y]);
    		while (y > a[i].y) putans(dfn[y]), y--;
    		if (a[i].lca) putans(a[i].lca);
    		an[a[i].num] = ans;
    		if (a[i].lca) putans(a[i].lca);
    	}
    	
    	for (int i = 1; i <= qn; i++) write(an[i]), putchar('
    ');
    	
    	return 0;
    }
    
  • 相关阅读:
    HelperC#常用的防sql注入的关键词检测
    工业自动化产线名词
    C#使用单例模式
    cmt焊接和mig焊区别
    数据库表命名规范
    UIImagePickerController类 照相 或者 从相册取相片 (iphone and ipad)
    UIActionSheet类 在 iphone和ipad 中的不同
    navigationBarrespondsToSelector方法 判断对象是否接受到了某个方法
    设置自定义UIButton的背景图片
    AVFoundation.framwork 及其 部分类的使用
  • 原文地址:https://www.cnblogs.com/Sakura-TJH/p/YBT_JPDH_6-4-3.html
Copyright © 2011-2022 走看看