题目大意



1.首先我们看一下操作1:实际上可以说成在所有位置上加上w−dist(x,y)w-dist(x,y)w−dist(x,y),因为dist(x,x)=0dist(x,x)=0dist(x,x)=0
2.我们知道dist(x,y)=dep[x]+dep[y]−2∗dep[lca(x,y)]dist(x,y)=dep[x]+dep[y]-2*dep[lca(x,y)]dist(x,y)=dep[x]+dep[y]−2∗dep[lca(x,y)]
3.代入化简w−dep[x]−dep[y]+2∗dep[lca(x,y)]w-dep[x]-dep[y]+2*dep[lca(x,y)]w−dep[x]−dep[y]+2∗dep[lca(x,y)]
我们将这个式子拆开来看:
(1):w−dep[x]w-dep[x]w−dep[x]
(2):dep[y]dep[y]dep[y]
(3):2∗dep[lca(x,y)]2*dep[lca(x,y)]2∗dep[lca(x,y)]

对于式子1,这是所有点都要加的,我们可以用一个全局变量统计一下ans1+=w−dep[x]ans1+=w-dep[x]ans1+=w−dep[x]
对于式子2是一个定值:为了计算减了几次我们用numnumnum统计操作1的次数
对于式子3x与所有的y的LCA都是x到根节点1【假设的】路径上的点x与所有的y的LCA都是x到根节点1【假设的】路径上的点x与所有的y的LCA都是x到根节点1【假设的】路径上的点


如何查询答案呢?
关键是式子3:
这时候我们就要用到树剖去维护了
加上2∗dep[lca(x,y)]2*dep[lca(x,y)]2∗dep[lca(x,y)]实际上就是相当于给1−>lca的路径上边权加21->lca的路径上边权加21−>lca的路径上边权加2
由于对于所有点的lca都是一条从1−>x1->x1−>x的路径,所有修改就是在1−>x1->x1−>x链上面每个点+2+2+2


假如你要查询y点的值:就是ans1−num∗dep[y]+query(1,y);ans1-num*dep[y]+query(1,y);ans1−num∗dep[y]+query(1,y);
这里为什么是直接query(1,y)query(1,y)query(1,y)呢?
因为每次我们只是修改中心点到根节点的链上面的信息如果你y点到根节点路径和这个相交的话交点就是LCA,交点下面是0,交点上面是修改过的,所以直接询问query(1,y);


操作2相当于对这个点额外减掉一些值:开个ad数组维护一下就好了


#include <iostream>
#include <cstdio>
#include <stack>
#include <sstream>
#include <limits.h>
#include <vector>
#include <map>
#include <cstring>
#include <deque>
#include <cmath>
#include <iomanip>
#include <queue>
#include <algorithm>
#include <set>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define _for(i,a,b) for( int i = (a); i < (b); ++i)
#define _rep(i,a,b) for( int i = (a); i <= (b); ++i)
#define for_(i,a,b) for( int i = (a); i >= (b); -- i)
#define rep_(i,a,b) for( int i = (a); i > (b); -- i)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define LLF 0x3f3f3f3f3f3f3f3f
#define hash Hash
#define next Next
#define count Count
#define pb push_back
#define f first
#define s second
using namespace std;
const int N = 3e5+10, mod = 1e9 + 9;
const long double eps = 1e-5;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double,double> PDD;
template<typename T> void read(T &x)
{x = 0;char ch = getchar();ll f = 1;while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args)
{read(first);read(args...);
}
int T;
int n, m;
struct node {int to, next;
}e[N];
int head[N],cnt;
//.................................建图
inline void add(int from, int to)
{e[cnt] = {to,head[from]};head[from] = cnt ++;
}
//..................................
ll fa[N], dep[N], siz[N], son[N];
//每个点的父节点,深度,子树大小,重儿子是谁
inline void dfs1(int u, int f)
{fa[u] = f, dep[u] = dep[f] + 1, siz[u] = 1;int max_size = -1;for(int i = head[u]; ~i; i = e[i].next){int v = e[i].to;if(v == f) continue;dfs1(v,u);siz[u] += siz[v];if(siz[v] > max_size){son[u] = v;max_size = siz[v];}}
}//..................................
ll tim, dfn[N], top[N];//dfs序,重链顶部
inline void dfs2(int u, int t) // 节点重链的顶部
{dfn[u] = ++ tim, top[u] = t;if(!son[u]) return;dfs2(son[u],t);//先跑重链for(int i = head[u]; ~i; i = e[i].next){int v = e[i].to;if(v == fa[u] || v == son[u]) continue;dfs2(v,v);}
}
//....................................线段树
ll tr[N << 2], tag[N << 2];
inline void pushup(int rt)
{tr[rt] = (tr[rt << 1] + tr[rt << 1|1]);
}inline void pushdown(int rt, int l, int r)
{if(tag[rt]){tag[rt << 1] += tag[rt];tag[rt << 1|1] += tag[rt];tr[rt << 1] = (tr[rt << 1] + 1ll * (mid - l + 1) * tag[rt]);tr[rt << 1|1] = (tr[rt << 1|1] + 1ll * (r - mid) * tag[rt]);tag[rt] = 0;}
}inline void build(int rt, int l , int r)
{if(l == r){tr[rt] = 0;return;}build(Lson), build(Rson);pushup(rt);
}inline void modify(int rt, int l, int r, int posl, int posr, int val)
{if(posl <= l && r <= posr){tag[rt] += val;tr[rt] = (tr[rt] + 1ll * (r - l + 1) * val);return;}pushdown(rt, l, r);if(posl <= mid) modify(Lson,posl,posr,val);if(posr > mid) modify(Rson,posl,posr,val);pushup(rt);
} inline ll query(int rt, int l, int r, int posl, int posr)
{if(posl <= l && posr >= r) return tr[rt];pushdown(rt,l,r);ll res = 0;if(posl <= mid) res = (res + query(Lson,posl, posr));if(posr > mid) res = (res + query(Rson,posl,posr));return res;
}
//....................................树剖链上操作
inline void mchain(int x, int y, ll z)
{while(top[x] != top[y]){if(dep[top[x]] < dep[top[y]]) swap(x,y);modify(1,1,n,dfn[top[x]],dfn[x],z);x = fa[top[x]];}if(dep[x] > dep[y]) swap(x,y);modify(1,1,n,dfn[x],dfn[y],z);
}inline ll qchain(int x, int y)
{ll res = 0;while(top[x] != top[y]){if(dep[top[x]] < dep[top[y]]) swap(x,y);res += query(1,1,n,dfn[top[x]],dfn[x]);x = fa[top[x]];}if(dep[x] > dep[y]) swap(x,y);res += query(1,1,n,dfn[x],dfn[y]);return res;
}
//...........................................
ll ad[N];
ll num, ans1;
//............................................
inline void init()
{num = ans1 = cnt = tim = 0;ms(ad,0), ms(head,-1), ms(tag,0);ms(son,0);dep[1] = 0;
}
int main()
{read(T);while(T --){init();read(n,m);_for(i,0,n-1){int l, r;read(l,r);add(l,r);add(r,l);}dfs1(1,1);dfs2(1,1);build(1,1,n);while(m --){int op,x,y;read(op);if(op == 1){read(x,y);num ++;ans1 += y - dep[x];mchain(1,x,2);}else if(op == 2){read(y);int v = ans1 - num * dep[y] + qchain(1,y);if(v > ad[y]) ad[y] = v;}else {read(y);printf("%lld\n",ans1 - num * dep[y] + qchain(1,y)-ad[y]);}}}return 0;
}

2020牛客多校第7场C-A National Pandemic[树链剖分+思维]相关推荐

  1. 牛客多校7 - A National Pandemic(树链剖分+线段树)

    题目链接:点击查看 题目大意:给出一棵树,再给出 m 次操作,每次操作分为三种类型,dist( x , y ) 代表点 x 和点 y 之间的距离: 1 pos val:将点 pos 位置的值增加 va ...

  2. 2020牛客多校第1场H-Minimum-cost Flow

    解题思路: 首先我们要从费用流mcmf的算法入手:因为它每次增广是再费用增广路上跑的,根据贪心的思想费用小的路基本上能运多少就尽量运多少,所以我们可以假设初始的边容量是1,只跑一遍mcmf.记录一下每 ...

  3. 数论分块 ---- 2020牛客多校第7场H-Dividing[思维+数论分块]

    题目大意: 解题思路:很明显满足条件的点是n%k==0∣∣n%k==1n\%k==0||n\%k==1n%k==0∣∣n%k==1 1.因为nnn是从111开始的如果一直乘以k[n=n∗k]k[n=n ...

  4. 2020牛客多校第5场B-Graph完全图异或最小生成树

    因为这里边是可以任意加的但是要保证联通性所有这里可以看成一个完全图,每条边的权值=a[u]^a[v] 1.那么我们可以将每个点的权值sort一遍,将每个a[i],从高位到低位,按照最高位的1出现的顺序 ...

  5. 2020牛客多校第3场:Two Matchings[找规律+dp]

    题目链接 解题思路:这题规律......无语: #include <iostream> #include <cstdio> #include <stack> #in ...

  6. 2020牛客多校第3场:[Points Construction Problem + 思维题+构造]

    题目链接 题目大意:就是给你n个边长为1的正方形,要求用这些正方形拼成周长为m的图形,并输出这些正方形的坐标,如果没有输出No 首先如果这些正方形都零散分布那么周长就是4∗n4*n4∗n,如果将这些正 ...

  7. 2020牛客多校第三场[C Operation Love+基础计算几何 判断多边形顺逆时针]

    题目链接 题目大意:就是给你两个左右手的模型,下面给出这两只手通过平移变换之后坐标问你这只手是左手还是右手?[题目保证坐标是按照顺时针或者逆时针给出的] 解题思路:首先我们先观察一下这只右手:假如数据 ...

  8. 贪心 ---- 2020牛客多校第3场[Clam and Fish+贪心]

    题目链接 解题思路:1.根据贪心的思想肯定是如果是第2或者第3种状态肯定是钓鱼且不需要鱼饵的,如果是在第0种状态有鱼饵肯定也钓鱼,对于第1种状态就是可以钓鱼也可以造鱼饵的状态我们如何考虑 2.我们从后 ...

  9. exgcd ---- 2020牛客多校第三场:[Fraction Construction Problem:exgcd+思维题]

    题目链接 题目大意:就是给你两个数a,ba,ba,b叫你求满足下面三个条件的c,d,e,fc,d,e,fc,d,e,f 1.cd−ef=ab1.{c\over d}-{e\over f}={a\ove ...

最新文章

  1. 客户信贷评级 Python 实战
  2. QT-第一个程序 Hello QT , 以及QT creator介绍
  3. python中类似对象吗_确定对象是否为Python中类似字节的对象的正确方法是什么?...
  4. 详解malloc,calloc,realloc原理及其模拟实现
  5. swift学习笔记之-协议
  6. 一句话讲明白 WebAssembly、微前端等技术背后的核心
  7. [外挂1] MFC 鼠标位置设置
  8. jQuery选择器--总结
  9. 怎么在bios里设置光驱启动 bios设置光驱启动图文教程
  10. leetcode-3:最长无重复字串
  11. kibana 写两个查询条件_Kibana使用之Lucene的语法查询
  12. 杰理之电脑连接样机蓝牙,开启音量同步,电脑无法大范围调节音量【篇】
  13. ACPI 待机/睡眠/休眠有啥区别?
  14. artemis mq配置开机启动 (centos7)(artemis Init Script)
  15. C++学习路线及推荐书籍
  16. 微信公众号菜单html5,Vue.js 实现微信公众号菜单编辑器功能(一)
  17. Command ‘netstat‘ not found:解决办法
  18. 前端 简单实现应用商店list
  19. Linux 中如何开启端口
  20. python 物理实验_物理实验

热门文章

  1. call ret指令的总结
  2. 深度学习七个实用技巧
  3. OpenCV中的透视变换介绍
  4. 图像配准的前世今生:从人工设计特征到深度学习
  5. Mac下pycharm如何安装tensorflow
  6. 对于SD-WAN安全的5个误区
  7. LaTex in Markdown
  8. 第三次Scream冲刺
  9. Webpack 代码分离
  10. 【Zookeeper】源码分析之Leader选举(一)