类似SPOJ QTREE模板题,还是要注意跳过LCA!!!(因为用最深的点权维护边权,LCA其实是上一个点的边权,不管update还是query)
只不过多了个取相反数操作
关于区间取相反数,如果是维护区间和,就加个负号;但如果是维护最大值,应该最大值最小值互换。
注释部分,表示按位取反如何维护最值(与本题无关)
①POJ 3237 Tree
#include <stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
using namespace std;
const int maxn = 100000+10;
typedef long long ll;
const int inf=0x3f3f3f3f;
int w[maxn];
int N, Q;
struct
{
int to,next,w;
}e[maxn<<2];
int head[maxn<<1],edgeNum;
struct
{
int u,v;
}edge[maxn<<1];
void add(int u,int v,int w)
{
e[edgeNum].next = head[u];
e[edgeNum].to = v;
e[edgeNum].w=w;
head[u] = edgeNum++;
}
/*-------------------------树剖------------------------------*/
int deep[maxn],fa[maxn],siz[maxn],son[maxn];
void dfs1(int u,int pre,int d)
{
deep[u] = d;
fa[u] = pre;
siz[u] = 1;
son[u] = 0;
for(int i=head[u];~i;i=e[i].next)
{
int v = e[i].to;
if(v!=pre)
{
dfs1(v,u,d+1);
siz[u] += siz[v];
if(siz[v]>siz[son[u]])
son[u] = v;
}
}
}
int top[maxn],id[maxn],rk[maxn],cnt;
void dfs2(int u,int t)
{
top[u] = t;
id[u] = ++cnt;
rk[cnt] = u;
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!=son[u]&&v!=fa[u])
dfs2(v,v);
}
}
/*-------------------------树剖------------------------------*/
/*-------------------------线段树------------------------------*/
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
int sum[maxn<<2],neg[maxn<<2],maxv[maxn<<2],minv[maxn<<2],add1[maxn<<2],mult[maxn<<2];//取反标记
void pushup(int rt)
{
// sum[rt] = (sum[rt<<1] + sum[rt<<1|1]);
maxv[rt] =max(maxv[rt<<1],maxv[rt<<1|1]);
minv[rt]=min(minv[rt<<1],minv[rt<<1|1]);
}
void pushdown(int rt,int l,int r)
{
if(neg[rt]){
//异或
neg[rt<<1]^=1;
neg[rt<<1|1]^=1;
swap(minv[rt<<1],maxv[rt<<1]);
minv[rt<<1]=-minv[rt<<1];
maxv[rt<<1]=-maxv[rt<<1];
swap(minv[rt<<1|1],maxv[rt<<1|1]);
minv[rt<<1|1]=-minv[rt<<1|1];
maxv[rt<<1|1]=-maxv[rt<<1|1];
neg[rt]=0;
}
// if(add1[rt]||mult[rt]!=1){
// add1[rt<<1] *= mult[rt], add1[rt<<1] += add1[rt];
// add1[rt<<1|1] *= mult[rt], add1[rt<<1|1] += add1[rt];
// mult[rt<<1] *= mult[rt];
// mult[rt<<1|1] *= mult[rt];
//
// sum[rt<<1] *= mult[rt], sum[rt<<1] += add1[rt] * l;
// sum[rt<<1|1] *= mult[rt], sum[rt<<1|1] += add1[rt] * r;
//
// add1[rt] = 0;
// mult[rt] = 1;
// }
}
void build(int l,int r,int rt)//单点更新
{
{
// sum[rt] = 0;
maxv[rt]=0;
minv[rt]=0;
neg[rt]=0;
if(l==r)return ;
}
int m = l + r >> 1;
build(lson);
build(rson);
// pushup(rt);
}
void change(int val,int q,int l,int r,int rt)//单点更新
{
if(l==r)
{
// sum[rt] = val;
maxv[rt]=val;
minv[rt]=val;
neg[rt]=0;
return ;
}
int m = l + r >> 1;
pushdown(rt,m-l+1,r-m);
if(q<=m)
change(val,q,lson);
else
change(val,q,rson);
pushup(rt);
}
void update2(int L,int R,int l,int r,int rt)
{
if(L <= l && r <= R)
{
neg[rt]^=1;
// mult[rt]*=-1,add1[rt]*=-1,add1[rt] +=-1;
//sum[rt] =-sum[rt];
//cout<<maxv[rt]<<" "<<minv[rt]<<endl;
swap(maxv[rt],minv[rt]);
maxv[rt]=-maxv[rt],minv[rt]=-minv[rt];
//cout<<maxv[rt]<<" "<<minv[rt]<<endl;
return ;
}
int m = l + r >> 1;
pushdown(rt,m-l+1,r-m);
if(L<=m)
update2(L,R,lson);
if(R>m)
update2(L,R,rson);
pushup(rt);
}
int query(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R)
return sum[rt];
int m = l + r >> 1,ans = 0;
pushdown(rt,m-l+1,r-m);
if(L<=m)
ans = (ans + query(L,R,lson));
if(R>m)
ans = (ans + query(L,R,rson));
return ans;
}
int querymax(int L,int R,int l,int r,int rt){
if (L<=l&&r<=R){
return maxv[rt];
}
int m=(l+r)>>1,ans=-inf;//注意负数①
pushdown(rt,m-l+1,r-m);
if (L<=m)ans=max(ans,querymax(L,R,lson));
if (R>m)ans=max(ans,querymax(L,R,rson));
pushup(rt);
return ans;
}
/*-------------------------线段树------------------------------*/
/*-----------------------树剖加线段树--------------------------*/
void update2(int x,int y)
{
while(top[x]!=top[y])
{
if(deep[top[x]]<deep[top[y]])
swap(x,y);
update2(id[top[x]],id[x],1,cnt,1);
x = fa[top[x]];
}
// if(x==y)return ;
if(deep[x]>deep[y])
swap(x,y);
update2(id[x]+1,id[y],1,cnt,1);//跳过LCA(深度小的),所以+1
}
int query(int x,int y)
{
int ans = 0;
while(top[x] != top[y])
{
if(deep[top[x]] < deep[top[y]])
swap(x,y);
ans = (ans + query(id[top[x]],id[x],1,cnt,1));//这里下标从1开始
x = fa[top[x]];
}
if(deep[x]>deep[y])
swap(x,y);
ans = (ans + query(id[x]+1,id[y],1,cnt,1));//跳过LCA(深度小的),所以+1
return ans;
}
int querymax(int x,int y)
{
int ans =-inf;//注意负数②
while(top[x] != top[y])
{
if(deep[top[x]] < deep[top[y]])
swap(x,y);
ans = max(ans ,querymax(id[top[x]],id[x],1,cnt,1));
x = fa[top[x]];
}
// if(x==y)return ans;
if(deep[x]>deep[y])
swap(x,y);
ans = max(ans ,querymax(id[x]+1,id[y],1,cnt,1));//跳过LCA(深度小的),所以+1
return ans;
}
/*-----------------------树剖加线段树--------------------------*/
void init()
{
memset(head,-1,sizeof(head));
cnt = edgeNum = 0;
memset(son,0,sizeof(son)) ;//这个也要初始化
}
int u, v, l, r,z;
int main()
{
int T;
scanf("%d",&T) ;
while(T--){
scanf("%d",&N);
init();
for(int i=1;i<N;++i)
{
//w[i] = 0;
scanf("%d%d%d",&u,&v,&w[i]);
edge[i].u=u;
edge[i].v=v;//真正的边数
add(u,v,w[i]);//边数*2
add(v,u,w[i]);
}
dfs1(1,0,0);
dfs2(1,1);
//build(1,N,1);//也可不build
for(int i=1;i<N;i++){
int tmp=deep[edge[i].u] > deep[edge[i].v] ? edge[i].u : edge[i].v;
change(w[i],id[tmp],1,N,1);
}
while(1)
{
char p[10];
scanf("%s",p);
if(p[0]=='D')break;//这里就要break!
scanf("%d%d",&r,&z);
if(p[0]=='C'){
r=deep[edge[r].u] > deep[edge[r].v] ? edge[r].u : edge[r].v;
change(z,id[r],1,N,1) ;
}
else if(p[0]=='Q')printf("%d\n",querymax(r,z));
else if(p[0]=='N') update2(r,z);
}
}
return 0;
}
②BZOJ 2157 旅游
多了两个询问最大最小值而已
#include <stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
using namespace std;
const int maxn = 200000+10;
typedef long long ll;
const int inf=0x3f3f3f3f;
int w[maxn];
int N, Q;
struct
{
int to,next,w;
}e[maxn<<2];
int head[maxn<<1],edgeNum;
struct
{
int u,v;
}edge[maxn<<1];
void add(int u,int v,int w)
{
e[edgeNum].next = head[u];
e[edgeNum].to = v;
e[edgeNum].w=w;
head[u] = edgeNum++;
}
/*-------------------------树剖------------------------------*/
int deep[maxn],fa[maxn],siz[maxn],son[maxn];
void dfs1(int u,int pre,int d)
{
deep[u] = d;
fa[u] = pre;
siz[u] = 1;
son[u] = 0;
for(int i=head[u];~i;i=e[i].next)
{
int v = e[i].to;
if(v!=pre)
{
dfs1(v,u,d+1);
siz[u] += siz[v];
if(siz[v]>siz[son[u]])
son[u] = v;
}
}
}
int top[maxn],id[maxn],rk[maxn],cnt;
void dfs2(int u,int t)
{
top[u] = t;
id[u] = ++cnt;
rk[cnt] = u;
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!=son[u]&&v!=fa[u])
dfs2(v,v);
}
}
/*-------------------------树剖------------------------------*/
/*-------------------------线段树------------------------------*/
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
int sum[maxn<<2],neg[maxn<<2],maxv[maxn<<2],minv[maxn<<2],add1[maxn<<2],mult[maxn<<2];//取反标记
void pushup(int rt)
{
sum[rt] = (sum[rt<<1] + sum[rt<<1|1]);
maxv[rt] =max(maxv[rt<<1],maxv[rt<<1|1]);
minv[rt]=min(minv[rt<<1],minv[rt<<1|1]);
}
void pushdown(int rt,int l,int r)
{
if(neg[rt]){
//异或
neg[rt<<1]^=1;
neg[rt<<1|1]^=1;
sum[rt<<1]=-sum[rt<<1];
sum[rt<<1|1]=-sum[rt<<1|1];
swap(minv[rt<<1],maxv[rt<<1]);
minv[rt<<1]=-minv[rt<<1];
maxv[rt<<1]=-maxv[rt<<1];
swap(minv[rt<<1|1],maxv[rt<<1|1]);
minv[rt<<1|1]=-minv[rt<<1|1];
maxv[rt<<1|1]=-maxv[rt<<1|1];
neg[rt]=0;
}
}
void build(int l,int r,int rt)//单点更新
{
{
sum[rt] = 0;
maxv[rt]=0;
minv[rt]=0;
neg[rt]=0;
if(l==r)return ;
}
int m = l + r >> 1;
build(lson);
build(rson);
// pushup(rt);
}
void change(int val,int q,int l,int r,int rt)//单点更新
{
if(l==r)
{
sum[rt] = val;
maxv[rt]=val;
minv[rt]=val;
neg[rt]=0;//不会变成相反数了!
return ;
}
int m = l + r >> 1;
pushdown(rt,m-l+1,r-m);
if(q<=m)
change(val,q,lson);
else
change(val,q,rson);
pushup(rt);
}
void update2(int L,int R,int l,int r,int rt)
{
if(L <= l && r <= R)
{
neg[rt]^=1;
sum[rt] =-sum[rt];
swap(maxv[rt],minv[rt]);
maxv[rt]=-maxv[rt],minv[rt]=-minv[rt];
return ;
}
int m = l + r >> 1;
pushdown(rt,m-l+1,r-m);
if(L<=m)
update2(L,R,lson);
if(R>m)
update2(L,R,rson);
pushup(rt);
}
int query(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R)
return sum[rt];
int m = l + r >> 1,ans = 0;
pushdown(rt,m-l+1,r-m);
if(L<=m)
ans = (ans + query(L,R,lson));
if(R>m)
ans = (ans + query(L,R,rson));
//pushup(rt);
return ans;
}
int querymax(int L,int R,int l,int r,int rt){
if (L<=l&&r<=R){
return maxv[rt];
}
int m=(l+r)>>1,ans=-inf;//注意负数①
pushdown(rt,m-l+1,r-m);
if (L<=m)ans=max(ans,querymax(L,R,lson));
if (R>m)ans=max(ans,querymax(L,R,rson));
pushup(rt);
return ans;
}
int querymin(int L,int R,int l,int r,int rt){
if (L<=l&&r<=R){
return minv[rt];
}
int m=(l+r)>>1,ans=inf;
pushdown(rt,m-l+1,r-m);
if (L<=m)ans=min(ans,querymin(L,R,lson));
if (R>m)ans=min(ans,querymin(L,R,rson));
pushup(rt);
return ans;
}
/*-------------------------线段树------------------------------*/
/*-----------------------树剖加线段树--------------------------*/
void update2(int x,int y)
{
while(top[x]!=top[y])
{
if(deep[top[x]]<deep[top[y]])
swap(x,y);
update2(id[top[x]],id[x],1,cnt,1);
x = fa[top[x]];
}
// if(x==y)return ;
if(deep[x]>deep[y])
swap(x,y);
update2(id[x]+1,id[y],1,cnt,1);
}
int query(int x,int y)
{
int ans = 0;
while(top[x] != top[y])
{
if(deep[top[x]] < deep[top[y]])
swap(x,y);
ans = (ans + query(id[top[x]],id[x],1,cnt,1));//这里下标从1开始
x = fa[top[x]];
}
if(deep[x]>deep[y])
swap(x,y);
ans = (ans + query(id[x]+1,id[y],1,cnt,1));
return ans;
}
int querymax(int x,int y)
{
int ans =-inf;//注意负数②
while(top[x] != top[y])
{
if(deep[top[x]] < deep[top[y]])
swap(x,y);
ans = max(ans ,querymax(id[top[x]],id[x],1,cnt,1));
x = fa[top[x]];
}
// if(x==y)return ans;
if(deep[x]>deep[y])
swap(x,y);
ans = max(ans ,querymax(id[x]+1,id[y],1,cnt,1));//跳过LCA(深度小的),所以+1
return ans;
}
int querymin(int x,int y)
{
int ans =inf;
while(top[x] != top[y])
{
if(deep[top[x]] < deep[top[y]])
swap(x,y);
ans = min(ans ,querymin(id[top[x]],id[x],1,cnt,1));
x = fa[top[x]];
}
// if(x==y)return ans;
if(deep[x]>deep[y])
swap(x,y);
ans = min(ans ,querymin(id[x]+1,id[y],1,cnt,1));//跳过LCA(深度小的),所以+1
return ans;
}
/*-----------------------树剖加线段树--------------------------*/
void init()
{
memset(head,-1,sizeof(head));
cnt = edgeNum = 0;
memset(son,0,sizeof(son)) ;//这个也要初始化!!!
}
int u, v, l, r,z;
int main()
{
int T=1;
while(T--){
scanf("%d",&N);
init();
for(int i=1;i<N;++i)
{
scanf("%d%d%d",&u,&v,&w[i]);
++u,++v;//编号+1
edge[i].u=u;
edge[i].v=v;//真正的边数
add(u,v,w[i]);//边数*2
add(v,u,w[i]);
}
dfs1(1,0,0);
dfs2(1,1);
build(1,N,1);//可不要
for(int i=1;i<N;i++){
int tmp=deep[edge[i].u] > deep[edge[i].v] ? edge[i].u : edge[i].v;
change(w[i],id[tmp],1,N,1);
}
scanf("%d",&Q);
while(Q--)
{
char p[10];
scanf("%s",p);
if(p[0]=='D')break;//这里就要break!
scanf("%d%d",&r,&z);
r++,z++;//点编号从1开始
if(p[0]=='C'){
r--,z--;//那两个不是点编号
r=deep[edge[r].u] > deep[edge[r].v] ? edge[r].u : edge[r].v;
change(z,id[r],1,N,1) ;
}
else if(p[0]=='N') update2(r,z);
else if(p[0]=='S')printf("%d\n",query(r,z));
else if(p[1]=='A')printf("%d\n",querymax(r,z));
else if(p[1]=='I')printf("%d\n",querymin(r,z));
}
}
return 0;
}