CF1633F题解

· · 题解

CF1633F

题意简述

给定一棵 n 个点的树,初始时只有 1 号点被激活。

处理两种操作:

### 题目分析 首先考虑解决树不变时的问题。显然首先要选择与叶子节点直接相连的边,然后隔一条选一条,看是否合法。 如果我们设一个点的状态 $f_u=0/1$,且 $f_u=1$,当且仅当连接 $u$ 和其父节点的边被选择,那么我们对于一个叶子节点的选边就是把它到根的路径上所有的 $f_u$ 取反。 用树剖 + 线段树就可以很方便地维护这个区间取反的过程。我们还要在线段树中记录选择的边数 $cnt$。如果全局 $cnt=\frac{n}{2}$,那么就合法。 然后现在这道题是不断加点,因为新加的点肯定是叶子,所以我们上面的做法可以直接做这道题。至于输出方案,因为不超过 $10$ 次询问所以直接暴力 dfs 就可以了。 Code: ```cpp #include<bits/stdc++.h> #define ll long long using namespace std; const int N=2e5+10; int n,tot,h[N]; struct edge { int v,w,nxt; }e[N<<1]; void add(int u,int v,int w) { e[++tot]=(edge){v,w,h[u]}; h[u]=tot; } int fa[N],siz[N],dep[N],wson[N]; void prework(int u) { siz[u]=1; for(int i=h[u];i;i=e[i].nxt) { int v=e[i].v; if(v==fa[u])continue; fa[v]=u,dep[v]=dep[u]+1; prework(v),siz[u]+=siz[v]; if(siz[wson[u]]<siz[v])wson[u]=v; } } int dfn[N],id[N],idx,top[N],a[N]; void dfs(int u,int t) { top[u]=t,id[dfn[u]=++idx]=u; if(wson[u])dfs(wson[u],t); for(int i=h[u];i;i=e[i].nxt) { int v=e[i].v; if(v==wson[u])a[v]=e[i].w; if(v==fa[u]||v==wson[u])continue; dfs(v,v),a[v]=e[i].w; } } struct SegmentTree { ll sum[N<<2],s[N<<2]; int cnt[N<<2],tag[N<<2]; void pushup(int p){s[p]=s[p<<1]+s[p<<1|1],cnt[p]=cnt[p<<1]+cnt[p<<1|1];} void adtag(int p,int l,int r) { tag[p]^=1,cnt[p]=(r-l+1)-cnt[p],s[p]=sum[p]-s[p]; } void pushdown(int p,int l,int r) { if(!tag[p])return; int mid=(l+r)>>1; adtag(p<<1,l,mid),adtag(p<<1|1,mid+1,r); tag[p]=0; } void build(int p,int l,int r) { if(l==r){cnt[p]=(l==1),sum[p]=a[id[l]];return;} int mid=(l+r)>>1; build(p<<1,l,mid),build(p<<1|1,mid+1,r); pushup(p),sum[p]=sum[p<<1]+sum[p<<1|1]; } void upd(int p,int l,int r,int L,int R) { if(L<=l&&r<=R){adtag(p,l,r);return;} pushdown(p,l,r); int mid=(l+r)>>1; if(L<=mid)upd(p<<1,l,mid,L,R); if(R>mid)upd(p<<1|1,mid+1,r,L,R); pushup(p); } }segt; bool act[N],chs[N]; int acnt; vector<int>way; void getans(int u) { for(int i=h[u];i;i=e[i].nxt) { int v=e[i].v; if(v==fa[u]||!act[v])continue; getans(v); if(!chs[v])chs[u]=1,way.push_back(e[i].w); } } int main() { scanf("%d",&n); for(int i=1,x,y;i<n;i++) scanf("%d%d",&x,&y),add(x,y,i),add(y,x,i); prework(1),dfs(1,1),segt.build(1,1,n),act[1]=1,acnt=1; int op,u;ll ans=0; while(1) { scanf("%d",&op); if(op==1) { scanf("%d",&u); act[u]=1,acnt++; while(u) { segt.upd(1,1,n,dfn[top[u]],dfn[u]); u=fa[top[u]]; } if(segt.cnt[1]*2==acnt)ans=segt.s[1]; else ans=0; printf("%lld\n",ans),fflush(stdout); } else if(op==2) { if(ans) { way.resize(0),memset(chs,0,sizeof(chs)); getans(1),sort(way.begin(),way.end()); printf("%d ",(int)way.size()),fflush(stdout); for(int x:way)printf("%d ",x),fflush(stdout); puts(""),fflush(stdout); } else puts("0"),fflush(stdout); } else break; } return 0; } ```