給你一棵\(n\)個點的樹,每一個點初始的時候有一個爲\(1\)或\(0\)的權值,如今要支持兩種操做:ios
\(op(1,x)\):令\(x\)點的權值反轉c++
\(op(2,x,d)\):求距離\(x\)點\(\leq d\)的點中,權值爲\(1\)的點組成的連通塊個數(注意\(x\)點自己不算在內,也就是詢問\(x\)的時候要僞裝\(x\)是\(0\))數組
數據範圍:\(1\leq n,m\leq 10^5\)spa
智力康復qwq碼+調試搞了差很少一萬年也是服了qwq調試
操做看過去濃濃的動態點分氣息,而後連通塊計數直接轉成範圍內權值爲\(1\)的點的數量\(-\)知足兩個端點的權值都是\(1\)的邊數便可code
因此每一個分治中心上咱們要維護的東西就是:權值爲\(1\)的點的數量,兩個端點權值都是\(1\)的邊的數量ip
實現上的話就是樹狀數組搞一搞就行了get
而後關於修改操做:注意到一個點修改了以後,它連出去的邊都會被影響到,然而若是修改的複雜度跟點的度數掛鉤隨便一個菊花圖就涼了,因此考慮換一種方式統計string
咱們把邊的貢獻掛在原樹的父親那裏,而後對於每一個點維護一下原樹兒子中有多少個權值爲\(1\)的便可it
查詢的時候注意\(d\)要\(-1\),而後還有各類奇奇怪怪的邊界的細節== 而後我個蒟蒻就寫得極其醜陋了qwq
mark:連通塊仍是直接點數-邊數計算比較好。。把貢獻掛在「最上面那個點」上。。很明顯有不少不優秀的地方。。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int N=1e5+10,TOP=20,BIT=N*17*2; struct xxx{ int y,nxt; }a[N*2]; char s[N]; int h[N],st[N],cnt[N]; int n,m,tot,q; namespace Bit{/*{{{*/ int c[BIT][2],st[N][2],mx[N][2]; int tot=0; //start from 0, +1 void modify(int which,int x,int delta,int op,int tp){//tp=0: - tp=1: + ++x; for (;x<=mx[which][op];x+=x&-x) c[st[which][op]+x][tp]+=delta; } int query(int which,int op,int x,int tp){ ++x; int ret=0; x=min(x,mx[which][op]); for (;x;x-=x&-x) ret+=c[st[which][op]+x][tp]; return ret; } }/*}}}*/ void add(int x,int y){a[++tot].y=y; a[tot].nxt=h[x]; h[x]=tot;} namespace OriT{/*{{{*/ int lis[N],dfn[N]; int dep[N],top[N],pre[N],son[N],sz[N]; int dfn_t; void predfs(int fa,int x,int d){ int u; dep[x]=d; ::cnt[x]=0; pre[x]=fa; son[x]=0; sz[x]=1; for (int i=h[x];i!=-1;i=a[i].nxt){ u=a[i].y; if (u==fa) continue; predfs(x,u,d+1); ::cnt[x]+=st[u]; sz[x]+=sz[u]; if (sz[u]>sz[son[x]]) son[x]=u; } } void dfs1(int fa,int x){ lis[++dfn_t]=x; dfn[x]=dfn_t; if (son[x]){ top[son[x]]=top[x]; dfs1(x,son[x]); } int u; for (int i=h[x];i!=-1;i=a[i].nxt){ u=a[i].y; if (u==fa||u==son[x]) continue; top[u]=u; dfs1(x,u); } } void prework(){ predfs(0,1,1); top[1]=1; dfn_t=0; dfs1(0,1); } int get_lca(int x,int y){ while (top[x]!=top[y]){ if (dep[top[x]]<dep[top[y]]) swap(x,y); x=pre[top[x]]; } return dep[x]<dep[y]?x:y; } int get_dis(int x,int y){ int lca=get_lca(x,y); return dep[x]+dep[y]-2*dep[lca]; } int jump(int x,int d){ int aim=dep[x]-d; if (!d) return x; while (dep[top[x]]>aim) x=pre[top[x]]; return lis[dfn[x]-(dep[x]-aim)]; } }/*}}}*/ namespace T{/*{{{*/ int pre[N],sz[N],mx[N]; int df_t[N]; int vis[N]; int cnt0[N],cnt1[N];//0=- 1=+ int rec[TOP+1][N][2]; int rt,rt_mx,mxdep; void get_sz(int fa,int x){ int u; sz[x]=1; mx[x]=0; for (int i=h[x];i!=-1;i=a[i].nxt){ u=a[i].y; if (u==fa||vis[u]) continue; get_sz(x,u); sz[x]+=sz[u]; mx[x]=max(mx[x],sz[u]); } } void get_rt(int Rt,int fa,int x){ int u; mx[x]=max(mx[x],sz[Rt]-sz[x]); if (mx[x]<rt_mx) rt=x,rt_mx=mx[x]; for (int i=h[x];i!=-1;i=a[i].nxt){ u=a[i].y; if (u==fa||vis[u]) continue; get_rt(Rt,x,u); } } void dfs(int rt_t,int fa,int x,int d,int op){ int u; mxdep=max(mxdep,d); cnt0[d]+=::st[x]?::cnt[x]:0; cnt1[d]+=::st[x]; rec[rt_t][x][op]=d; for (int i=h[x];i!=-1;i=a[i].nxt){ u=a[i].y; if (u==fa||vis[u]) continue; dfs(rt_t,x,u,d+1,op); } } void get_lis(int x,int rt,int which_t,int op){ mxdep=0; Bit::st[rt][op]=Bit::tot; if (op==0) dfs(which_t,0,rt,0,op); else dfs(which_t,0,x,0,op); Bit::mx[rt][op]=mxdep+1; Bit::tot+=Bit::mx[rt][op]; for (int i=0;i<=mxdep;++i){ Bit::modify(rt,i,cnt0[i],op,0); Bit::modify(rt,i,cnt1[i],op,1); cnt0[i]=0; cnt1[i]=0; } } void solve(int fa,int x){ int u,Rt; rt=0,rt_mx=n; get_sz(0,x); get_rt(x,0,x); Rt=rt; df_t[Rt]=df_t[fa]+1; pre[Rt]=fa; get_lis(x,Rt,df_t[Rt],0); get_lis(x,Rt,df_t[Rt],1); vis[Rt]=1; for (int i=h[Rt];i!=-1;i=a[i].nxt){ u=a[i].y; if (vis[u]) continue; solve(Rt,u); } } int query(int x,int aim,int d,int tp){//tp=0: - tp=1: + int dis=d-OriT::get_dis(x,aim),pos; int ret=dis>=0?Bit::query(x,0,dis,tp):0; if (pre[x]){ dis=d-OriT::get_dis(pre[x],aim)-1; if (dis>=0){ ret-=Bit::query(x,1,dis,tp); } ret+=query(pre[x],aim,d,tp); } return ret; } void modify(int x,int aim,int delta,int tp){//tp=0: - tp=1:+ if (!delta) return; Bit::modify(x,rec[df_t[x]][aim][0],delta,0,tp); if (pre[x]){ Bit::modify(x,rec[df_t[x]][aim][1],delta,1,tp); modify(pre[x],aim,delta,tp); } } }/*}}}*/ void modify(int x){ int delta=st[x]?-1:1; int fa=OriT::pre[x]; if (fa&&st[fa]) T::modify(fa,fa,delta,0); if (fa) cnt[fa]+=delta; T::modify(x,x,cnt[x]*delta,0); T::modify(x,x,delta,1); st[x]+=delta; } int query(int x,int d){ int tmp1,tmp2,fa=OriT::pre[x]; tmp1=T::query(x,x,d-1,0); tmp2=T::query(x,x,d,1); if (st[x]){ --tmp2; tmp1-=cnt[x]+st[fa]; } if (OriT::dep[x]>d){ x=OriT::jump(x,d-1); fa=OriT::pre[x]; tmp1+=st[x]&st[fa]; } return tmp2-tmp1; } void prework(){ OriT::prework(); T::solve(0,1); } int main(){ #ifndef ONLINE_JUDGE freopen("a.in","r",stdin); #endif int x,y,op,d; scanf("%d%d",&n,&m); memset(h,-1,sizeof(h)); tot=0; for (int i=1;i<n;++i){ scanf("%d%d",&x,&y); add(x,y); add(y,x); } scanf("%s",s+1); for (int i=1;i<=n;++i) st[i]=s[i]=='1'; prework(); for (int i=1;i<=m;++i){ scanf("%d",&op); if (op==1){ scanf("%d",&x); modify(x); } else{ scanf("%d%d",&x,&d); printf("%d\n",query(x,d)); } } } /* 6 3 1 2 1 3 1 4 2 5 3 6 111000 2 1 2 2 4 2 1 1 2 4 2 */