PID 60 線段樹樹形轉線性
阿新 • • 發佈:2019-02-16
題意:有一棵樹,開始的時候樹上的每一個節點都沒有打結,實現兩個操作 給樹上的某一個節點及其所有子節點翻轉
即每個打結的節點變成沒有節,沒打結的打結,然後詢問打結的節點的個數在某一棵子樹中的個數
解法:利用線段樹將節點轉化為線性結構,然後對重新標號的線段進行操作即可
#include<cstdio> #include<vector> #include<iostream> using namespace std; #define maxn 111111 #define ls (rt<<1) #define rs (rt<<1|1) #define mid ((l+r)>>1) int ll[maxn],rr[maxn],cnt; int rev[maxn<<2],sum[maxn<<2]; vector<int>g[maxn]; void up(int rt){sum[rt]=sum[ls]+sum[rs];} void build(int rt,int l,int r){ rev[rt]=0,sum[rt]=0; if(l==r)return ; build(ls,l,mid); build(rs,mid+1,r); } void down(int rt,int l,int r){ if(rev[rt]){ sum[ls]=(mid-l+1)-sum[ls]; sum[rs]=(r-(mid+1)+1)-sum[rs]; rev[ls]^=1;rev[rs]^=1; rev[rt]=0; } } void ins(int rt,int l,int r,int L,int R){ if(L<=l&&r<=R){ sum[rt]=(r-l+1)-sum[rt]; rev[rt]^=1; return ; } down(rt,l,r); if(L<=mid)ins(ls,l,mid,L,R); if(mid<R)ins(rs,mid+1,r,L,R); up(rt); } int query(int rt,int l,int r,int L,int R){ if(L<=l&&r<=R){ return sum[rt]; }down(rt,l,r); int ans=0; if(L<=mid)ans+=query(ls,l,mid,L,R); if(mid<R)ans+=query(rs,mid+1,r,L,R); return ans; } void dfs(int u,int f){ ll[u]=++cnt; for(int i=0;i<g[u].size();++i){ int v=g[u][i]; if(v==f)continue; dfs(v,u); } rr[u]=cnt; } char op[22]; int main(){ cnt=0;int n,u,v,m;scanf("%d",&n); for(int i=1;i<n;++i){ scanf("%d%d",&u,&v); g[u].push_back(v); g[v].push_back(u); } dfs(1,-1); build(1,1,n); scanf("%d",&m); // for(int i=1;i<=n;++i)printf("%d %d\n",ll[i],rr[i]); while(m--){ scanf("%s%d",op,&u); if(*op=='Q')printf("%d\n",query(1,1,n,ll[u],rr[u])); else{ ins(1,1,n,ll[u],rr[u]); } } return 0; }