裸树剖
因为没有赋size[u]=1写T了T^T
这个东西有区间可并性QAQ
#include
#include
#include
#include
#define maxn 100010
using namespace std;
int n, q;
struct Node{int l, r, val, pre, suf, lazy;};
int c[maxn], dfn[maxn], dfs_clock;
struct Segment{
Node t[maxn << 2];
#define lc id<<1
#define rc id<<1|1
void pushdown(int id){
if(t[id].lazy){
t[lc].lazy = t[rc].lazy = t[id].lazy;
t[lc].pre = t[lc].suf = t[rc].pre = t[rc].suf = t[id].lazy;
t[lc].val = t[rc].val = 1;
t[id].lazy = 0;
}
}
void pushup(int id){
t[id].val = t[lc].val + t[rc].val - (t[lc].suf == t[rc].pre);
t[id].pre = t[lc].pre;
t[id].suf = t[rc].suf;
}
void build(int id, int l, int r){
t[id].l = l, t[id].r = r;
if(l == r){t[id].val = 1;t[id].pre = t[id].suf = c[dfn[l]];return;}
int mid = l + r >> 1;
build(lc, l, mid);
build(rc, mid+1, r);
pushup(id);
}
void update(int id, int l, int r, int val){
if(t[id].l == l && t[id].r == r){
t[id].val = 1;
t[id].pre = t[id].suf = t[id].lazy = val;
return;
}
pushdown(id);
int mid = t[id].l + t[id].r >> 1;
if(r <= mid)update(lc, l, r, val);
else if(l > mid)update(rc, l, r, val);
else{
update(lc, l, mid, val);
update(rc, mid+1, r, val);
}
pushup(id);
}
Node ask(int id, int l, int r){
if(t[id].l == l && t[id].r == r)
return t[id];
pushdown(id);
int mid = t[id].l + t[id].r >> 1;
if(r <= mid)return ask(lc, l, r);
if(l > mid)return ask(rc, l, r);
Node ret1 = ask(lc, l, mid), ret2 = ask(rc, mid+1, r), ret;
ret.val = ret1.val + ret2.val - (ret1.suf == ret2.pre);
ret.pre = ret1.pre, ret.suf = ret2.suf;
return ret;
}
}T;
struct Edge{int to, next;}edge[maxn << 1];
int h[maxn], cnt;
void add(int u, int v){
cnt ++;
edge[cnt].to = v;
edge[cnt].next = h[u];
h[u] = cnt;
}
const int root = 1;
int size[maxn], top[maxn], pos[maxn], son[maxn], fa[maxn], dep[maxn];
void dfs1(int u){
dep[u] = dep[fa[u]] + 1;
size[u] = 1;
for(int i = h[u]; i; i = edge[i].next){
int v = edge[i].to;
if(v == fa[u])continue;
fa[v] = u;
dfs1(v);
size[u] += size[v];
if(size[v] > size[son[u]])
son[u] = v;
}
}
void dfs2(int u, int tp){
top[u] = tp;
pos[u] = ++ dfs_clock;
dfn[dfs_clock] = u;
if(son[u])dfs2(son[u], tp);
for(int i = h[u]; i; i = edge[i].next){
int v = edge[i].to;
if(v == fa[u] || v == son[u])continue;
dfs2(v, v);
}
}
void Modify(int u, int v, int c){
while(top[u] != top[v]){
if(dep[top[u]] < dep[top[v]])
swap(u, v);
T.update(1, pos[top[u]], pos[u], c);
u = fa[top[u]];
}
if(dep[u] < dep[v])swap(u, v);
T.update(1, pos[v], pos[u], c);
}
Node ret;
int solve(int u, int v){
int last1 = 0, last2 = 0, ans = 0;
while(top[u] != top[v]){
if(dep[top[u]] < dep[top[v]])
swap(u, v), swap(last1, last2);
ret = T.ask(1, pos[top[u]], pos[u]);
ans += ret.val;
if(last1 == ret.suf)ans --;
last1 = ret.pre;
u = fa[top[u]];
}
if(dep[u] < dep[v])swap(u, v), swap(last1, last2);
ret = T.ask(1, pos[v], pos[u]);
ans += ret.val;
if(last2 == ret.pre)ans --;
if(last1 == ret.suf)ans --;
return ans;
}
int main(){
scanf("%d%d", &n, &q);
for(int i = 1; i <= n; i ++)
scanf("%d", &c[i]);
int u, v, d;
for(int i = 1; i < n; i ++){
scanf("%d%d", &u, &v);
add(u, v), add(v, u);
}
dfs1(root);
dfs2(root, root);
T.build(1, 1, n);
for(int i = 1; i <= q; i ++){
char QAQ = getchar();
for(; QAQ < '!'; QAQ = getchar());
if(QAQ == 'C'){
scanf("%d%d%d", &u, &v, &d);
Modify(u, v, d);
}
else{
scanf("%d%d", &u, &v);
printf("%d\n", solve(u, v));
}
}
return 0;
}
注意到树剖维护的线段树是一个dfs序
所以查询一棵子树就变成了dfs序上的一段区间
然后。。
换根嘛
就是查询的区间不同啦
一共就三种情况嘛~
No1.u=root 那全局最小值就OK啦
No2.root在u的子树外 那就是u的子树中的最小值啊~
No3.root在u的子树内
就是这样啦
我们要找到root属于哪个子树(但是千万不要找到fa[u]!)
想象一下把root拎起来,然后查询蓝色部分+u的地方的最小值!
然后就是查询除了v这棵子树的最小值啦
(话说菊花树怎么破)
然后神犇机智的回答
遥远的国度菊花树的解决方法很简单
用vector存下每个节点的儿子
之后预处理对vector排序
之后每次查询二分就可以了
%%%%%%%%%%%%
#include
#define maxn 100010
using namespace std;
typedef long long ll;
int n, m;
struct Node{
int l, r;
ll lazy, min, val;
};
ll a[maxn];
int dfn[maxn], dfs_clock;
struct Segment{
Node t[maxn << 2];
#define lc id<<1
#define rc id<<1|1
void pushup(int id){
t[id].min = min(t[lc].min, t[rc].min);
}
void pushdown(int id){
if(t[id].lazy){
t[lc].lazy = t[rc].lazy = t[id].lazy;
t[lc].min = t[rc].min = t[id].lazy;
t[lc].val = t[rc].val = t[id].lazy;
t[id].lazy = 0;
}
}
void build(int id, int l, int r){
t[id].l = l, t[id].r = r;
if(l == r){
t[id].val = t[id].min = a[dfn[l]];
return;
}
int mid = l+r >> 1;
build(lc, l, mid);
build(rc, mid+1, r);
pushup(id);
}
void cover(int id, int l, int r, ll c){
if(t[id].l == l && t[id].r == r){
t[id].lazy = t[id].val = t[id].min = c;
return;
}
pushdown(id);
int mid = t[id].l + t[id].r >> 1;
if(r <= mid)cover(lc, l, r, c);
else if(l > mid)cover(rc, l, r, c);
else{
cover(lc, l, mid, c);
cover(rc, mid+1, r, c);
}
pushup(id);
}
ll ask(int id, int l, int r){
if(t[id].l == l && t[id].r == r)
return t[id].min;
pushdown(id);
int mid = t[id].l + t[id].r >> 1;
if(r <= mid)return ask(lc, l, r);
if(l > mid)return ask(rc, l, r);
return min(ask(lc, l, mid), ask(rc, mid+1, r));
}
}T;
struct Edge{int to, next;}edge[maxn << 1];
int h[maxn], cnt;
void add(int u, int v){
cnt ++;
edge[cnt].to = v;
edge[cnt].next = h[u];
h[u] = cnt;
}
int root;
int fa[maxn], dep[maxn], size[maxn], son[maxn], top[maxn], pos[maxn];
int L[maxn], R[maxn];
void dfs1(int u){
dep[u] = dep[fa[u]] + 1;
size[u] = 1;
for(int i = h[u]; i; i = edge[i].next){
int v = edge[i].to;
if(v == fa[u])continue;
fa[v] = u;
dfs1(v);
size[u] += size[v];
if(size[v] > size[son[u]])
son[u] = v;
}
}
void dfs2(int u, int tp){
L[u] = pos[u] = ++ dfs_clock;
top[u] = tp;
dfn[dfs_clock] = u;
if(son[u])dfs2(son[u], tp);
for(int i = h[u]; i; i = edge[i].next){
int v = edge[i].to;
if(v == son[u] || v == fa[u])continue;
dfs2(v, v);
}
R[u] = dfs_clock;
}
void Modify(int u, int v, ll c){
while(top[u] != top[v]){
if(dep[top[u]] < dep[top[v]])
swap(u, v);
T.cover(1, pos[top[u]], pos[u], c);
u = fa[top[u]];
}
if(dep[u] < dep[v])swap(u, v);
T.cover(1, pos[v], pos[u], c);
}
ll solve(int u){
if(u == root)return T.ask(1, 1, n);
if(pos[root] >= L[u] && pos[root] <= R[u]){
for(int i = h[u]; i; i = edge[i].next){
int v = edge[i].to;
if(v == fa[u])continue;
if(pos[root] >= L[v] && pos[root] <= R[v]){
u = v;
break;
}
}
ll t = 0x7fffffff;
if(L[u] - 1)t = T.ask(1, 1, L[u]-1);
if(R[u] < n)t = min(t, T.ask(1, R[u]+1, n));
return t;
}
return T.ask(1, L[u], R[u]);
}
int main(){
scanf("%d%d", &n, &m);
int u, v;
ll d;
for(int i = 1; i < n; i ++){
scanf("%d%d", &u, &v);
add(u, v), add(v, u);
}
for(int i = 1; i <= n; i ++)
scanf("%lld", &a[i]);
scanf("%d", &root);
dfs1(root);
dfs2(root, root);
T.build(1, 1, n);
int opt;
for(int i = 1; i <= m; i ++){
scanf("%d", &opt);
if(opt == 1)scanf("%d", &root);
else if(opt == 2){
scanf("%d%d%lld", &u, &v, &d);
Modify(u, v, d);
}
else{
scanf("%d", &u);
printf("%lld\n", solve(u));
}
}
return 0;
}
也是很重要的
如上题所示
有一棵点数为N的树,以点1为根,且树点有边权。然后有M个操作,分为三种:
操作1:把某个节点x的点权增加a。
操作2:把某个节点x为根的子树中所有点的点权都增加a。
操作3:询问某个节点x到根的路径中所有点的点权和。
如果把操作 贡献化ans = (dep[u] - (dep[x]-1)) * a
发现只需要维护一个K和一个B
然后dfs序中进栈用In表示,出栈用Out表示
#include
#define maxn 200010
using namespace std;
typedef long long ll;
struct Edge{
int to, next;
}edge[maxn];
int h[maxn], cnt, n, m;
void add(int u, int v){
cnt ++;
edge[cnt].to = v;
edge[cnt].next = h[u];
h[u] = cnt;
}
const int root = 1;
int a[maxn];
int In[maxn], Out[maxn], dfs_clock, fa[maxn];
int dep[maxn];
void dfs(int u){
In[u] = ++ dfs_clock;
dep[u] = dep[fa[u]] + 1;
for(int i = h[u]; i; i = edge[i].next){
if(edge[i].to == fa[u])continue;
fa[edge[i].to] = u;
dfs(edge[i].to);
}
Out[u] = dfs_clock;
}
struct BIT{
ll t[maxn];
#define lowbit(i) i&(~i+1)
void update(int pos, ll val){
if(!pos)return;
for(int i = pos; i <= n+1; i += lowbit(i))
t[i] += val;
}
ll ask(int pos){
if(!pos)return 0;
ll ret = 0;
for(int i = pos; i; i -= lowbit(i))
ret += t[i];
return ret;
}
}K, B;
void Modify(int x, ll a, int type){
if(type){
B.update(In[x], -a*(dep[x]-1));
B.update(Out[x]+1, a*(dep[x]-1));
K.update(In[x], a);
K.update(Out[x]+1, -a);
}
else B.update(In[x], a), B.update(Out[x]+1, -a);
}
ll ask(int x){
return K.ask(In[x]) * dep[x] + B.ask(In[x]);
}
int main(){
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i ++)
scanf("%d", &a[i]);
int u, v;
for(int i = 1; i < n; i ++){
scanf("%d%d", &u, &v);
add(u, v), add(v, u);
}
dfs(root);
for(int i = 1; i <= n; i ++){
B.update(In[i], a[i]);
B.update(Out[i]+1, -a[i]);
}
for(int i = 1; i <= m; i ++){
scanf("%d", &u);
if(u == 1){
scanf("%d%d", &u, &v);
Modify(u, v, 0);
}
else if(u == 2){
scanf("%d%d", &u, &v);
Modify(u, v, 1);
}
else{
scanf("%d", &u);
printf("%lld\n", ask(u));
}
}
return 0;
}