title: 线段树
date: 2022-05-13 00:05:51
tags:
线段树
动态开点
#include<bits/stdc++.h>
using namespace std;
const int N=1e7+5e6+10;
int ls[N],rs[N],root,sum[N],idx,lazy[N];
int n,q,ql,qr,k;
void pushup(int u){
sum[u]=sum[ls[u]]+sum[rs[u]];
}
void pushdown(int u,int l,int r){
if(lazy[u]==-1)return;
if(!ls[u])ls[u]=++idx;
if(!rs[u])rs[u]=++idx;
lazy[ls[u]]=lazy[rs[u]]=lazy[u];
int mid=l+r>>1;
sum[ls[u]]=(mid-l+1)*lazy[u];
sum[rs[u]]=(r-mid)*lazy[u];
lazy[u]=-1;
//动态开点的结点是不能写成递归的形式,要确切给定操作区间
}
void modify(int &u,int l,int r,int ql,int qr,int k){
if(!u)u=++idx;
if(r<ql||l>qr)return;
if(l>=ql&&r<=qr){
sum[u]=(r-l+1)*k;
lazy[u]=k;
return;
}
pushdown(u,l,r);
int mid=l+r>>1;
if(ql<=mid)modify(ls[u],l,mid,ql,qr,k);
if(qr>mid)modify(rs[u],mid+1,r,ql,qr,k);
pushup(u);
}
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n>>q;
for(int i=0;i<N;i++)lazy[i]=-1;
modify(root,1,n,1,n,0);
//根节点为root的点占据的区间是1-n
//这个操作是把【1,n】这个区间推平为0
while(q--){
cin>>ql>>qr>>k;
modify(root,1,n,ql,qr,2-k);
cout<<n-sum[root]<<'\n';
}
}
把边权化为点权
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+10,M=2*N;
int h[N],e[M],ne[M],w[M],idx,cnt,fa[N],top[N],nw[N],dep[N],tmp[N];
int id[N],sz[N],son[N];
typedef pair<int, int> PII;
PII ab[N];
int n,x,y,a,b,c,m;
string op;
struct node{
int sum,max,min,lazy;
}t[N*4];
void add(int a,int b,int c){
e[++idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx;
}
void dfs1(int u,int father){
dep[u]=dep[father]+1,fa[u]=father,sz[u]=1;
for(int i=h[u];i;i=ne[i]){
int j=e[i];
if(j==father)continue;
dfs1(j,u);
tmp[j]=w[i];
sz[u]+=sz[j];
if(sz[son[u]]<sz[j])son[u]=j;
}
}
void dfs2(int x,int t){
id[x]=++cnt,nw[cnt]=tmp[x],top[x]=t;
if(son[x])dfs2(son[x],t);
for(int i=h[x];i;i=ne[i]){
int j=e[i];
if(j==fa[x]||j==son[x])continue;
dfs2(j,j);
}
}
void pushup(int u){
t[u].sum=t[u<<1].sum+t[u<<1|1].sum;
t[u].max=max(t[u<<1].max,t[u<<1|1].max);
t[u].min=min(t[u<<1].min,t[u<<1|1].min);
}
void pushdown(int u){
if(t[u].lazy==0)return;
auto &L=t[u<<1];
auto &R=t[u<<1|1];
L.lazy^=1,R.lazy^=1;
L.sum=-L.sum,L.max=-L.max,L.min=-L.min;
R.sum=-R.sum,R.max=-R.max,R.min=-R.min;
swap(L.max,L.min),swap(R.max,R.min);
t[u].lazy=0;
}
void build(int u=1,int l=1,int r=n){
t[u]={nw[l],nw[l],nw[l]};
if(l>=r)return;
int mid=l+r>>1;
build(u<<1,l,mid),build(u<<1|1,mid+1,r);
pushup(u);
}
void modify(int u,int l,int r,int i,int k){
if(l==r){
t[u].sum=t[u].max=t[u].min=k;
return;
}
pushdown(u);
int mid=l+r>>1;
if(i<=mid)modify(u<<1,l,mid,i,k);
else modify(u<<1|1,mid+1,r,i,k);
pushup(u);
}
void update(int u,int l,int r,int ql,int qr,int lazy=1){
if(l>qr||r<ql)return;
if(l>=ql&&r<=qr){
t[u].sum=-t[u].sum;
t[u].max=-t[u].max;
t[u].min=-t[u].min;
swap(t[u].max,t[u].min);
t[u].lazy^=1;
return;
}
pushdown(u);
int mid=l+r>>1;
if(ql<=mid)update(u<<1,l,mid,ql,qr);
if(qr>mid)update(u<<1|1,mid+1,r,ql,qr);
pushup(u);
}
int qmax(int u,int l,int r,int ql,int qr){
if(l>qr||r<ql)return -1e9;
if(l>=ql&&r<=qr)return t[u].max;
pushdown(u);
int mid=l+r>>1;
int ans=-1e9;
if(ql<=mid)ans=max(ans,qmax(u<<1,l,mid,ql,qr));
if(qr> mid)ans=max(ans,qmax(u<<1|1,mid+1,r,ql,qr));
return ans;
}
int qmin(int u,int l,int r,int ql,int qr){
if(l>qr||r<ql)return 1e9;
if(l>=ql&&r<=qr)return t[u].min;
pushdown(u);
int mid=l+r>>1;
int ans=1e9;
if(ql<=mid)ans=min(ans,qmin(u<<1,l,mid,ql,qr));
if(qr> mid)ans=min(ans,qmin(u<<1|1,mid+1,r,ql,qr));
return ans;
}
int qsum(int u,int l,int r,int ql,int qr){
if(l>qr||r<ql)return 0;
if(l>=ql&&r<=qr)return t[u].sum;
pushdown(u);
int mid=l+r>>1;
int ans=0;
if(ql<=mid)ans+=qsum(u<<1,l,mid,ql,qr);
if(qr> mid)ans+=qsum(u<<1|1,mid+1,r,ql,qr);
return ans;
}
/* 上面是线段树,下面是树链剖分*/
void update(int x,int y){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
update(1,1,n,id[top[x]],id[x]);
x=fa[top[x]];
}
if(dep[x]>dep[y])swap(x,y);
if(x!=y)update(1,1,n,id[x]+1,id[y]);
}
int qmax(int x,int y){
int ans=-1e9;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
ans=max(ans, qmax(1,1,n,id[top[x]],id[x]) );
x=fa[top[x]];
}
if(dep[x]>dep[y])swap(x,y);
if(x!=y)ans=max(ans,qmax(1,1,n,id[x]+1,id[y]));
return ans;
}
int qmin(int x,int y){
int ans=1e9;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
ans=min(ans, qmin(1,1,n,id[top[x]],id[x]));
x=fa[top[x]];
}
if(dep[x]>dep[y])swap(x,y);
if(x!=y)ans=min(ans,qmin(1,1,n,id[x]+1,id[y]));
return ans;
}
int qsum(int x,int y){
int ans=0;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
ans+=qsum(1,1,n,id[top[x]],id[x]);
x=fa[top[x]];
}
if(dep[x]>dep[y])swap(x,y);
if(x!=y)ans+=qsum(1,1,n,id[x]+1,id[y]);
return ans;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=1;i<n;i++){
cin>>a>>b>>c;
a++,b++;
ab[i]={a,b};
add(a,b,c);
add(b,a,c);
}
dfs1(1,0);
dfs2(1,1);
build(1,1,n);
cin>>m;
while(m--){
cin>>op>>x>>y;
if(op=="C"){
int a=ab[x].first;
int b=ab[x].second;
if(dep[a]<dep[b])swap(a,b);
modify(1,1,n,id[a],y);
continue;
}
x++,y++;
if(op=="N")update(x,y);
if(op=="SUM")cout<<qsum(x,y)<<'\n';
if(op=="MAX")cout<<qmax(x,y)<<'\n';
if(op=="MIN")cout<<qmin(x,y)<<'\n';
}
}
拓展
如果是在有颜色的树上修改呢
颜色个数为1e5
也就是说这道题要动态开点来写
#include<bits/stdc++.h>
#define int long long
#define remove _
using namespace std;
const int N=1e6+10,M=2*N;
int h[N],e[M],ne[M],w[M],idx,cnt,fa[N],top[N],nw[N],dep[N],tmp[N];
int id[N],sz[N],son[N];
typedef pair<int, int> PII;
PII ab[N];
int n,x,y,a,b,c,m;
string op;
int rt;
// struct node{
// int sum,max,min,lazy;
// }t[N*4];
struct node{
int sum,max,min,lazy;
int ls,rs;
}t[N*4];
int root[N];
int color[N];
void add(int a,int b,int c){
e[++idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx;
}
void dfs1(int u,int father){
dep[u]=dep[father]+1,fa[u]=father,sz[u]=1;
for(int i=h[u];i;i=ne[i]){
int j=e[i];
if(j==father)continue;
dfs1(j,u);
tmp[j]=w[i];
sz[u]+=sz[j];
if(sz[son[u]]<sz[j])son[u]=j;
}
}
void dfs2(int x,int t){
id[x]=++cnt,nw[cnt]=tmp[x],top[x]=t;
if(son[x])dfs2(son[x],t);
for(int i=h[x];i;i=ne[i]){
int j=e[i];
if(j==fa[x]||j==son[x])continue;
dfs2(j,j);
}
}
void pushup(int u){
t[u].sum=t[t[u].ls].sum+t[t[u].rs].sum;
t[u].max=max(t[t[u].ls].max,t[t[u].rs].max);
t[u].min=min(t[t[u].ls].min,t[t[u].rs].min);
}
void pushdown(int u){
if(t[u].lazy==0)return;
if(!t[u].ls)t[u].ls=++rt;
if(!t[u].rs)t[u].rs=++rt;
auto &L=t[t[u].ls];
auto &R=t[t[u].rs];
L.lazy^=1,R.lazy^=1;
L.sum=-L.sum,L.max=-L.max,L.min=-L.min;
R.sum=-R.sum,R.max=-R.max,R.min=-R.min;
swap(L.max,L.min),swap(R.max,R.min);
t[u].lazy=0;
}
// void build(int u=1,int l=1,int r=n){
// t[u]={nw[l],nw[l],nw[l]};
// if(l>=r)return;
// int mid=l+r>>1;
// build(u<<1,l,mid),build(u<<1|1,mid+1,r);
// pushup(u);
// }
void modify(int &u,int l,int r,int i,int k){
if(!u)u=++rt;
if(l==r){
t[u].sum=t[u].max=t[u].min=k;
return;
}
pushdown(u);
int mid=l+r>>1;
if(i<=mid)modify(t[u].ls,l,mid,i,k);
else modify(t[u].rs,mid+1,r,i,k);
pushup(u);
}
void remove(int &u,int l,int r,int i,int k){
if(l==r){
t[u].max=-1e9;
t[u].sum=0;
t[u].min=1e9;
t[u].lazy=0;
return;
}
int mid=l+r>>1;
pushdown(u);
if(i<=mid)remove(t[u].ls,l,mid,i,k);
else remove(t[u].rs,mid+1,r,i,k);
pushup(u);
}
void update(int &u,int l,int r,int ql,int qr,int lazy=1){
if(l>qr||r<ql)return;
if(!u)u=++rt;
if(l>=ql&&r<=qr){
t[u].sum=-t[u].sum;
t[u].max=-t[u].max;
t[u].min=-t[u].min;
swap(t[u].max,t[u].min);
t[u].lazy^=1;
return;
}
pushdown(u);
int mid=l+r>>1;
if(ql<=mid)update(t[u].ls,l,mid,ql,qr);
if(qr>mid)update(t[u].rs,mid+1,r,ql,qr);
pushup(u);
}
int qmax(int u,int l,int r,int ql,int qr){
if(!u)return -1e9;
if(l>qr||r<ql)return -1e9;
if(l>=ql&&r<=qr)return t[u].max;
pushdown(u);
int mid=l+r>>1;
int ans=-1e9;
if(ql<=mid)ans=max(ans,qmax(t[u].ls,l,mid,ql,qr));
if(qr> mid)ans=max(ans,qmax(t[u].rs,mid+1,r,ql,qr));
return ans;
}
int qmin(int u,int l,int r,int ql,int qr){
if(!u)return 1e9;
if(l>qr||r<ql)return 1e9;
if(l>=ql&&r<=qr)return t[u].min;
pushdown(u);
int mid=l+r>>1;
int ans=1e9;
if(ql<=mid)ans=min(ans,qmin(t[u].ls,l,mid,ql,qr));
if(qr> mid)ans=min(ans,qmin(t[u].rs,mid+1,r,ql,qr));
return ans;
}
int qsum(int u,int l,int r,int ql,int qr){
if(!u)return 0;
if(l>qr||r<ql)return 0;
if(l>=ql&&r<=qr)return t[u].sum;
pushdown(u);
int mid=l+r>>1;
int ans=0;
if(ql<=mid)ans+=qsum(t[u].ls,l,mid,ql,qr);
if(qr> mid)ans+=qsum(t[u].rs,mid+1,r,ql,qr);
return ans;
}
/* 上面是线段树,下面是树链剖分*/
void update(int &o,int x,int y){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
update(o,1,n,id[top[x]],id[x]);
x=fa[top[x]];
}
if(dep[x]>dep[y])swap(x,y);
if(x!=y)update(o,1,n,id[x]+1,id[y]);
}
int qmax(int o,int x,int y){
int ans=-1e9;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
ans=max(ans, qmax(o,1,n,id[top[x]],id[x]) );
x=fa[top[x]];
}
if(dep[x]>dep[y])swap(x,y);
if(x!=y)ans=max(ans,qmax(o,1,n,id[x]+1,id[y]));
return ans;
}
int qmin(int o,int x,int y){
int ans=1e9;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
ans=min(ans, qmin(o,1,n,id[top[x]],id[x]));
x=fa[top[x]];
}
if(dep[x]>dep[y])swap(x,y);
if(x!=y)ans=min(ans,qmin(o,1,n,id[x]+1,id[y]));
return ans;
}
int qsum(int o,int x,int y){
int ans=0;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
ans+=qsum(o,1,n,id[top[x]],id[x]);
x=fa[top[x]];
}
if(dep[x]>dep[y])swap(x,y);
if(x!=y)ans+=qsum(o,1,n,id[x]+1,id[y]);
return ans;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=1;i<n;i++){
cin>>a>>b>>c;
a++,b++;
ab[i]={a,b};
add(a,b,c);
add(b,a,c);
}
dfs1(1,0);
dfs2(1,1);
//build(1,1,n);
for(int i=1;i<=n;i++)color[i]=1;
for(int i=1;i<=n;i++)modify(root[color[i]],1,n,id[i],tmp[i]);
cin>>m;
while(m--){
cin>>op>>x>>y;
if(op=="C"){
int a=ab[x].first;
int b=ab[x].second;
if(dep[a]<dep[b])swap(a,b);
remove(root[color[a]],1,n,id[a],0);
modify(root[color[a]],1,n,id[a],y);
continue;
}
x++,y++;
if(op=="N")update(root[color[x]],x,y);
if(op=="SUM")cout<<qsum(root[color[x]],x,y)<<'\n';
if(op=="MAX")cout<<qmax(root[color[x]],x,y)<<'\n';
if(op=="MIN")cout<<qmin(root[color[x]],x,y)<<'\n';
}
}
线段树合并
对每一个节点开一个权值线段树
用动态开点,不然会mle
而且不要直接#define int long long 只在关键变量开long long不然还是会MLE
#include<bits/stdc++.h>
// #define int long long
using namespace std;
const int N=1e5+10,M=2*N;
int h[N],e[M],ne[M],idx;
int n,m,c[N],root[N],cnt;
long long ans[N];
struct node{
int l,r;
long long sum;//主要颜色的编号和
int max;//出现最多颜色的次数
#define ls tr[u].l
#define rs tr[u].r
}tr[N*100];
void add(int a,int b){
e[++idx]=b,ne[idx]=h[a],h[a]=idx;
}
void pushup(int u){
tr[u].max=max(tr[ls].max,tr[rs].max);
if(tr[ls].max==tr[rs].max)tr[u].sum=tr[ls].sum+tr[rs].sum;
if(tr[ls].max >tr[rs].max)tr[u].sum=tr[ls].sum;
if(tr[ls].max <tr[rs].max)tr[u].sum=tr[rs].sum;
}
void pushdown(int u){
}
void modify(int &o,int l,int r,int i,int k){
if(!o)o=++cnt;
if(l==r){
tr[o].max=1;
tr[o].sum=k;
return;
}
int mid=l+r>>1;
if(i<=mid)modify(tr[o].l,l,mid,i,k);
else modify(tr[o].r,mid+1,r,i,k);
pushup(o);
}
int merge(int a,int b,int l,int r){//线段树合并
if(!a)return b;
if(!b)return a;//哪个没有就返回另一个点的编号
if(l==r){
tr[a].max+=tr[b].max;
return a;
}
int mid=l+r>>1;
tr[a].l=merge(tr[a].l,tr[b].l,l,mid);//合并a,b的左儿子
tr[a].r=merge(tr[a].r,tr[b].r,mid+1,r);//合并a,b的右儿子
pushup(a);
return a;
}
void cal(int u,int fa=0){
for(int i=h[u];i;i=ne[i]){
int j=e[i];
if(j==fa)continue;
cal(j,u);
root[u]=merge(root[u],root[j],1,n);
}
ans[u]=tr[root[u]].sum;
}
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)cin>>c[i];
for(int i=1;i<n;i++){
int a,b;
cin>>a>>b;
add(a,b);
add(b,a);
}
for(int i=1;i<=n;i++)modify(root[i],1,n,c[i],c[i]);
cal(1);
for(int i=1;i<=n;i++)cout<<ans[i]<<" ";
}