1
5 6
1 2
1 3
2 4
2 5
1 1 5
3 4
2 1
1 2 7
3 3
3 1
输出
3
9
6
题意:一棵树,三种操作:
1.一个中心城市x,所有 城市y的值 + =w-dist(x,y);
2.将城市x的值与0取min
3.询问单点的值。
下面是官方题解
题解:
2操作单独记录一个delta就能解决了。
对于1操作,我们考虑一次修改对y来说会增加w-dis(x,y)。 W-dis(x,y)=w - (dep(x) + dep(y)-2dep(lca))=w-dep(x)-dep(y)+2dep(lca)
所以,对于每次1操作,我们将其到根上所有点的cnt +=2,询问的时候那部分就是求它到根的权值和。
所以,树上路径加,路径查询,写个qtree改一下输出就好了。
那其实很多人上了点分,复杂度变成一个log,怎么更优就见仁见智了。
代码:
#include
#define mp make_pair
#define pb push_back
#define left lef
#define right righ
#define rep(i,n) for(long long i=1;i<=n;++i)
#define bit(i) __builtin_popcount(i)
#define x1 gtmsub
#define y1 gtmshb
#define x2 gtmjtjl
#define y2 gtmsf
using namespace std;
#define N 100020
#define LL long long
struct SegTree {
LL lazy[N*4], sum[N*4];
int n;
void init(int n1) {
n = n1;
memset(lazy, 0, sizeof(lazy));
memset(sum , 0, sizeof(sum ));
}
void pushdown(int p, int left, int right) {
if (lazy[p]) {
sum[p] += lazy[p] * (right - left + 1);
if (left != right) lazy[p<<1|0] += lazy[p], lazy[p<<1|1] += lazy[p];
lazy[p] = 0;
}
}
void pushup(int p, int left, int right) {
int mid = (left + right) >> 1;
pushdown(p<<1|0, left, mid);
pushdown(p<<1|1, mid+1, right);
sum[p] = sum[p<<1|0] + sum[p<<1|1];
}
void add(int p, int left, int right, int x, int y) {
pushdown(p, left, right);
if (x <= left && right <= y) {
lazy[p] ++;
pushdown(p, left, right);
return;
}
int mid = (left + right) >> 1;
if (x <= mid) add(p<<1|0, left, mid, x, y);
if (y > mid) add(p<<1|1, mid+1, right, x, y);
pushup(p, left, right);
}
void add(int x, int y) { add(1, 1, n, x, y); }
LL get(int p, int left, int right, int x, int y) {
pushdown(p, left, right);
if (x <= left && right <= y) {
return sum[p];
}
int mid = (left + right) >> 1;
LL s = 0;
if (x <= mid) s += get(p<<1|0, left, mid, x, y);
if (y > mid) s += get(p<<1|1, mid+1, right, x, y);
return s;
}
LL get(int x, int y) { if (x>y) return 0; return get(1, 1, n, x, y); }
} tree;
struct EDGE {
int adj, next;
} edge[N*2];
int n, q, top, to, gh[N];
int deep[N], father[N], son[N], size[N], Top[N], w[N];
LL answ, ans;
void addedge(int x, int y) {
edge[++top].adj = y;
edge[top].next = gh[x];
gh[x] = top;
}
void dfs(int x, int root=0) {
father[x] = root;
deep[x] = deep[root] + 1;
son[x] = 0; size[x] = 1;
int dd = 0;
for (int p=gh[x]; p; p=edge[p].next)
if (edge[p].adj != root) {
dfs(edge[p].adj, x);
size[x] += size[edge[p].adj];
if (size[edge[p].adj] > dd) {
dd = size[edge[p].adj];
son[x] = edge[p].adj;
}
}
}
void split(int x, int tp) {
w[x] = ++to; Top[x] = tp;
if (son[x]) split(son[x], tp);
for (int p=gh[x]; p; p=edge[p].next)
if (edge[p].adj != father[x] && edge[p].adj != son[x])
split(edge[p].adj, edge[p].adj);
}
void Init() {
memset(gh, 0, sizeof(gh));
top = to = 0;
scanf("%d%d", &n, &q);
for (int i=1;i<n;i++) {
int x, y;
scanf("%d%d", &x, &y);
addedge(x, y);
addedge(y, x);
}
dfs(1); split(1, 1);
tree.init(n);
}
LL query(int x, bool isq) {
int tx = Top[x]; LL anscnt = 0;
while (tx != 1) {
if (isq) anscnt += tree.get(w[tx], w[x]);
else tree.add(w[tx], w[x]);
x = father[tx];
tx = Top[x];
}
if (isq) anscnt += tree.get(w[1]+1, w[x]);
else tree.add(w[1] , w[x]);
return anscnt;
}
LL delta[N];
LL get(int x)
{
LL ans=0;
ans = 2LL * query(x, true);
ans += answ;
ans += -tree.get(w[1], w[1]) * (deep[x]-1);
return ans+delta[x];
}
void Solve() {
// Ans = sum(root) + dep(i) * cnt(root) - 2 sigma cnt(i) (i belongs to i --> root and root is not included)
int oper, x, d; answ = 0;
memset(delta,0,sizeof(delta));
while (q--) {
scanf("%d", &oper);
if (oper == 1)
{
scanf("%d%d", &x, &d);
answ += d - deep[x] + 1;
query(x, false);
}
else
if (oper == 2)
{
scanf("%d",&x);
LL tdelta=max(0ll,get(x));
delta[x]-=tdelta;
}
else
if (oper == 3)
{
scanf("%d", &x);
printf("%lld\n", get(x));
}
}
}
int main() {
int T;
cin>>T;
while (T--)
{
Init();
Solve();
}
return 0;
}