BZOJ1103: [POI2007]大都市meg
括号序·树状数组
题解:
首先求出括号序。如样例为1455422331
将进栈时打上标记1,出栈时打标记-1,这样已经退出的点的两个标记就会互相抵消
然后出栈序号与1号序号之间的权值和-1即为答案(排除1的影响)
修改时只要将对应标记变为0就可以了
Code:
#include <iostream>
#include <cstring>
#include <cstdio>
#define D(x) cout<<#x<<" = "<<x<<" "
#define E cout<<endl
using namespace std;
const int N = 500005;
int n,m,tim, s[N],t[N];
struct Edge{
int to,next;
} e[N*2];
int ec=0, head[N];
void add(int a,int b){
ec++; e[ec].to=b; e[ec].next=head[a]; head[a]=ec;
}
struct BIT{
int c[N*2], sz;
inline int lowbit(int x){ return x&(-x); }
void init(int _sz){ sz=_sz; memset(c,0,sizeof(c)); }
void add(int x,int d){ while(x<=sz){ c[x]+=d; x+=lowbit(x); } }
int sum(int x){ int ans=0; while(x>0){ ans+=c[x]; x-=lowbit(x); } return ans; }
} bit;
void dfs(int x,int f){
s[x]=++tim;
for(int i=head[x];i;i=e[i].next){
int v=e[i].to;
if(v==f) continue;
dfs(v,x);
}
t[x]=++tim;
}
int main(){
scanf("%d",&n);
int a,b; char op[5];
for(int i=1;i<n;i++){
scanf("%d%d",&a,&b);
add(a,b); add(b,a);
}
dfs(1,0); bit.init(tim);
for(int i=2;i<=n;i++){
bit.add(s[i],1); bit.add(t[i],-1);
}
scanf("%d",&m); m=m+n-1;
for(int i=1;i<=m;i++){
scanf("%s",op);
if(op[0]=='A'){
scanf("%d%d",&a,&b);
bit.add(s[b],-1); bit.add(t[b],1);
}
else{
scanf("%d",&a);
printf("%d\n",bit.sum(s[a]));
}
}
}
本文介绍了BZOJ1103大都市meg问题的解决思路,通过构建括号序列并利用树状数组来快速查询区间权值和,实现了动态更新节点状态的功能。

426

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



