显然这道题是一个树状结构。
对于两种操作
设未安装为0,已安装为1
install x,相当于查询从0到x的路径中有多少个0,再将路径中的所有值置为1
uninstall x,相当于查询x的子树中有多少个1,再将子树中的所有值置为0
其实就是模板题,为了方便实现,我将0和1互换,这样的话install过程直接区间求和与区间修改。
而uninstall过程子树求和后再用子树的大小减去求得和,得到子树中0的个数。修改直接修改子树即可。
#include<bits/stdc++.h>
#define fer(i,j,n) for(int i=j;i<=n;i++)
#define far(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
#define pa pair<int,int>
const int maxn=1000010;
const int INF=1e9+7;
using namespace std;
/*----------------------------------------------------------------------------*/
inline ll read()
{
char ls;ll x=0,sng=1;
for(;ls<'0'||ls>'9';ls=getchar())if(ls=='-')sng=-1;
for(;ls>='0'&&ls<='9';ls=getchar())x=x*10+ls-'0';
return x*sng;
}
/*----------------------------------------------------------------------------*/
ll n,m;
struct kaga
{
int next;
int point;
}e[maxn];
struct akagi
{
int l,r;
ll sum,lazy;
}tr[maxn];
int last[maxn],k=0,fa[maxn],size[maxn],son[maxn],belong[maxn],hashh[maxn],hashv[maxn],dep[maxn],v[maxn];
void sumup(int x)
{
tr[x].sum=tr[x<<1].sum+tr[x<<1|1].sum;
return ;
}
void pushdown(int x)
{
int y=tr[x].lazy;
if(y==1)
{
tr[x<<1].lazy=1;
tr[x<<1].sum=(tr[x<<1].r-tr[x<<1].l+1);
tr[x<<1|1].lazy=1;
tr[x<<1|1].sum=(tr[x<<1|1].r-tr[x<<1|1].l+1);
}
if(y==2)
{
tr[x<<1].lazy=2;
tr[x<<1].sum=0;
tr[x<<1|1].lazy=2;
tr[x<<1|1].sum=0;
}
tr[x].lazy=0;
}
void build(int x,int l,int r)
{
int mid=(l+r)>>1;
tr[x].l=l;tr[x].r=r;
if(l==r)
{
tr[x].sum=1;
tr[x].lazy=0;
return ;
}
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
sumup(x);
return ;
}
void change(int x,int L,int R,int val)
{
int l=tr[x].l,r=tr[x].r,mid=(l+r)>>1;
if(L<=l&&r<=R)
{
if(val==1)
{
tr[x].sum=r-l+1;
tr[x].lazy=1;
}
else
if(val==2)
{
tr[x].sum=0;
tr[x].lazy=2;
}
return ;
}
pushdown(x);
if(R<=mid)change(x<<1,L,R,val);
else if(L>mid)change(x<<1|1,L,R,val);
else change(x<<1,L,mid,val),change(x<<1|1,mid+1,R,val);
sumup(x);
return ;
}
ll query(int x,int L,int R)
{
int l=tr[x].l,r=tr[x].r,mid=(l+r)>>1;
if(L<=l&&r<=R)return tr[x].sum;
pushdown(x);
if(R<=mid)query(x<<1,L,R);
else if(L>mid)query(x<<1|1,L,R);
else return query(x<<1,L,mid)+query(x<<1|1,mid+1,R);
}
void add_edge(int x,int y)
{
e[++k].next=y;e[k].point=last[x];last[x]=k;
}
void insert(int x,int y)
{
add_edge(x,y);
add_edge(y,x);
}
void dfs1(int x,int fat)
{
fa[x]=fat;
dep[x]=dep[fat]+1;
size[x]=1;
for(int j=last[x];j;j=e[j].point)
{
int y=e[j].next;
if(y==fat)continue;
dfs1(y,x);
size[x]+=size[y];
if(!son[x]||size[y]>size[son[x]])
son[x]=y;
}
}
void dfs2(int x,int top)
{
belong[x]=top;
hashh[x]=++k;
hashv[k]=x;
if(!son[x])return ;
dfs2(son[x],top);
for(int j=last[x];j;j=e[j].point)
{
int y=e[j].next;
if(y!=son[x]&&y!=fa[x])
dfs2(y,y);
}
}
void update(int x,int y,int val)
{
int topx=belong[x];
int topy=belong[y];
while(topx!=topy)
{
if(dep[topx]<dep[topy])
{
swap(x,y);
swap(topx,topy);
}
change(1,hashh[topx],hashh[x],val);
x=fa[topx];
topx=belong[x];
}
if(dep[x]>dep[y])swap(x,y);
change(1,hashh[x],hashh[y],val);
}
ll sigma(int x,int y)
{
ll sum=0;
int topx=belong[x];
int topy=belong[y];
while(topx!=topy)
{
if(dep[topx]<dep[topy])
{
swap(x,y);
swap(topx,topy);
}
sum+=query(1,hashh[topx],hashh[x]);
x=fa[topx];
topx=belong[x];
}
if(dep[x]>dep[y])swap(x,y);
sum+=query(1,hashh[x],hashh[y]);
return sum;
}
void updateson(int x,int val)
{
int left=hashh[x];
int right=hashh[x]+size[x]-1;
change(1,left,right,val);
}
ll sigmason(int x)
{
int left=hashh[x];
int right=hashh[x]+size[x]-1;
return right-left+1-query(1,left,right);
}
int main()
{
n=read();
fer(i,2,n)
{
int x=read()+1;
insert(x,i);
}
k=0;
dfs1(1,0);
dfs2(1,1);
build(1,1,n);
m=read();
fer(i,1,m)
{
char ls[10];
scanf("%s",ls);
if(ls[0]=='i')
{
int x=read()+1;
cout<<sigma(1,x)<<endl;
update(1,x,2);
}
else
{
int x=read()+1;
cout<<sigmason(x)<<endl;
updateson(x,1);
}
}
}
本文介绍了一种基于树状结构的问题解决方法,针对特定操作进行了优化。通过使用线段树,解决了节点安装与卸载的问题,并实现了高效的区间查询与修改。文章详细展示了如何构建线段树并进行区间更新与查询。
453

被折叠的 条评论
为什么被折叠?



