zoukankan      html  css  js  c++  java
  • 【bzoj3052】[wc2013]糖果公园 带修改树上莫队

    题目描述

    给出一棵n个点的树,每个点有一个点权,点权范围为1~m。支持两种操作:(1)修改一个点的点权 (2)对于一条路径,求$sumlimits_{i=1}^msumlimits_{j=1}^{s_i}V_iW_j$,其中$s_i$表示这条链上权值为i的点数。

    输入

    输出

    样例输入

    4 3 5
    1 9 2
    7 6 5 1
    2 3
    3 1
    3 4
    1 2 3 2
    1 1 2
    1 4 2
    0 2 1
    1 1 2
    1 4 2

    样例输出

    84
    131
    27
    84


    题解

    带修改树上莫队

    带修改树上莫队——普通莫队的 带修改进化版+上树树上进化版。

    带修改莫队:每块大小$n^{frac 23}$,分别以左端点所在块、右端点所在块、时间(这次询问之前的修改次数)为第一、二、三关键字排序,然后暴力移动三个指针。

    树上莫队:分块方法改成树分块(树分块方法参考 王室联邦),自然序改成DFS序(然而带修改莫队用不到自然序,这里只是提一嘴),暴力移动指针。这里可以把点权加到边权上(链上LCA只在统计答案是算上),以避免特判。

    把它们结合起来本题就做完了。把树分块,然后按照带修改莫队处理即可。

    几点注意:

    求LCA要用非朴素LCA(因为不仅仅在移动指针时需要求LCA,点权加到边权上时统计答案也需要处理LCA)

    修改要记录是从什么改到什么,因为有反向修改(时间指针左移)操作。

    答案会爆int,故需要long long。

    时间复杂度$O(n^{frac 53})$

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define N 100010
    using namespace std;
    const int b = 1200;
    typedef long long ll;
    int v[N] , w[N] , head[N] , to[N << 1] , next[N << 1] , ce , type[N];
    int fa[N][20] , deep[N] , log[N] , tot , sta[N] , top , bl[N] , num;
    int pc[N] , wc[N] , vc[N] , vis[N] , cnt[N];
    ll ans , ret[N];
    struct data
    {
    	int lp , rp , cp , id;
    	bool operator<(const data &a)const
    	{
    		return bl[lp] == bl[a.lp] ? bl[rp] == bl[a.rp] ? cp < a.cp : bl[rp] < bl[a.rp] : bl[lp] < bl[a.lp];
    	}
    }a[N];
    void add(int x , int y)
    {
    	to[++ce] = y , next[ce] = head[x] , head[x] = ce;
    }
    void dfs(int x)
    {
    	int i , now = top;
    	for(i = 1 ; (1 << i) <= deep[x] ; i ++ ) fa[x][i] = fa[fa[x][i - 1]][i - 1];
    	for(i = head[x] ; i ; i = next[i])
    	{
    		if(to[i] != fa[x][0])
    		{
    			fa[to[i]][0] = x , deep[to[i]] = deep[x] + 1 , dfs(to[i]);
    			if(top - now >= b)
    			{
    				num ++ ;
    				while(top != now) bl[sta[top -- ]] = num;
    			}
    		}
    	}
    	sta[++top] = x;
    }
    int lca(int x , int y)
    {
    	int i;
    	if(deep[x] < deep[y]) swap(x , y);
    	for(i = log[deep[x] - deep[y]] ; ~i ; i -- )
    		if(deep[x] - deep[y] >= (1 << i))
    			x = fa[x][i];
    	if(x == y) return x;
    	for(i = log[deep[x]] ; ~i ; i -- )
    		if(deep[x] >= (1 << i) && fa[x][i] != fa[y][i])
    			x = fa[x][i] , y = fa[y][i];
    	return fa[x][0];
    }
    void rev(int x)
    {
    	if(vis[x]) ans -= (ll)w[cnt[type[x]]] * v[type[x]] , cnt[type[x]] -- , vis[x] = 0;
    	else cnt[type[x]] ++ , ans += (ll)w[cnt[type[x]]] * v[type[x]] , vis[x] = 1;
    }
    int main()
    {
    	int n , m , q , i , j , x , y , opt , cc = 0 , ln = 1 , rn = 1 , now = 0;
    	scanf("%d%d%d" , &n , &m , &q);
    	for(i = 1 ; i <= m ; i ++ ) scanf("%d" , &v[i]);
    	for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &w[i]);
    	for(i = 2 ; i <= n ; i ++ ) scanf("%d%d" , &x , &y) , add(x , y) , add(y , x) , log[i] = log[i >> 1] + 1;
    	dfs(1);
    	while(top) bl[sta[top -- ]] = num;
    	for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &type[i]);
    	for(i = 1 ; i <= q ; i ++ )
    	{
    		scanf("%d" , &opt);
    		if(opt)
    		{
    			scanf("%d%d" , &a[i - cc].lp , &a[i - cc].rp) , a[i - cc].cp = cc , a[i - cc].id = i - cc;
    			if(bl[a[i - cc].lp] > bl[a[i - cc].rp]) swap(a[i - cc].lp , a[i - cc].rp);
    		}
    		else cc ++ , scanf("%d%d" , &pc[cc] , &vc[cc]) , wc[cc] = type[pc[cc]] , type[pc[cc]] = vc[cc];
    	}
    	for(i = cc ; i ; i -- ) type[pc[i]] = wc[i];
    	sort(a + 1 , a + q - cc + 1);
    	for(i = 1 ; i <= q - cc ; i ++ )
    	{
    		x = lca(ln , a[i].lp);
    		for(j = ln ; j != x ; j = fa[j][0]) rev(j);
    		for(j = a[i].lp ; j != x ; j = fa[j][0]) rev(j);
    		x = lca(rn , a[i].rp);
    		for(j = rn ; j != x ; j = fa[j][0]) rev(j);
    		for(j = a[i].rp ; j != x ; j = fa[j][0]) rev(j);
    		ln = a[i].lp , rn = a[i].rp , x = lca(ln , rn) , rev(x);
    		while(now < a[i].cp)
    		{
    			now ++ ;
    			if(vis[pc[now]]) cnt[vc[now]] ++ , ans += (ll)w[cnt[vc[now]]] * v[vc[now]] - (ll)w[cnt[wc[now]]] * v[wc[now]] , cnt[wc[now]] -- ;
    			type[pc[now]] = vc[now];
    		}
    		while(now > a[i].cp)
    		{
    			if(vis[pc[now]]) cnt[wc[now]] ++ , ans += (ll)w[cnt[wc[now]]] * v[wc[now]] - (ll)w[cnt[vc[now]]] * v[vc[now]] , cnt[vc[now]] -- ;
    			type[pc[now]] = wc[now];
    			now -- ;
    		}
    		ret[a[i].id] = ans;
    		rev(x);
    	}
    	for(i = 1 ; i <= q - cc ; i ++ ) printf("%lld
    " , ret[i]);
    	return 0;
    }
    

     

  • 相关阅读:
    echarts基础使用
    将数据表中的热词统计结果用echarts热词云展示
    LInux下bash: wget: command not found解决方法
    利用Jieba对txt进行分词操作并保存在数据库中
    idea运行Guns示例demo
    浅谈一下mshta在CVE201711882里的命令构造
    CVE201711882 POC 全版本通杀
    本地复现Flash 0day漏洞(CVE20184878)
    Oracle安装错误
    oracle远程连接服务器出现 ORA12170 TNS:连接超时 解决办法
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7741808.html
Copyright © 2011-2022 走看看