F.DFS
题意:给你一颗初始树,然后两种操作,一个是原来两个点没有边然后加边,另外一个是两个点有边,删除边(不包括初始树边)。问你每次操作后,有多少个合法的点。合法点的定义:以这点为dfs的起点建出来的树与初始树是否不一样,如果每次都是不一样的,那么这就是不合格的点,否则就是合格的点。
题解:
我只要求得x,y这个环,不包括x,y内的所有点,和与环内点相连的点,都是不合格的点,我用总数减去不合格的。建议去手推一下具体是哪些点是不合格的,这是比较容易能看出来的。
#include<bits/stdc++.h>
#define ls o*2
#define rs o*2+1
#define m (l+r)/2
using namespace std;
const int maxn = 2e5+10;
int tr[maxn*4],lz[maxn*4];
int f[maxn][20],d[maxn],l[maxn],r[maxn],cnt;
vector<int>G[maxn];
map<int,int>mp[maxn];
void push(int o,int l,int r)
{
if(lz[o])tr[o] = r-l+1;
else if(l==r) tr[o] = 0;
else tr[o] = tr[ls]+tr[rs];
}
void up(int o,int l,int r,int ql,int qr,int p)
{
if(ql>qr)return ;
if(ql<=l&&qr>=r) {
lz[o] += p ;
push(o,l,r);
return ;
}
if(ql<=m) up(ls,l,m,ql,qr,p);
if(qr>m) up(rs,m+1,r,ql,qr,p);
push(o,l,r);
}
void dfs(int u,int fa,int dep)
{
f[u][0] = fa;
d[u] = dep;
l[u] = ++cnt;
for(auto v:G[u])
if(v!=fa) dfs(v,u,dep+1);
r[u] = cnt;
}
int main()
{
int u,v;
int n,q;scanf("%d%d",&n,&q);
for(int i=1;i<n;i++){
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1,0,1);
for(int j=1;j<20;j++)
for(int i=1;i<=n;i++)
f[i][j] = f[f[i][j-1]][j-1];
int p;
for(int i=1;i<=q;i++)
{
scanf("%d%d",&u,&v);
if(l[u]>l[v]) swap(u,v);
if(!mp[u][v]) mp[u][v] = 1 ,p = 1;
else mp[u][v] = 0 , p = -1;
if(r[u]>=r[v]){
int x = v;
for(int j=19;j>=0;j--)
if(d[f[x][j]]>d[u]) x = f[x][j];
up(1,1,n,l[x],l[v]-1,p) , up(1,1,n,r[v]+1,r[x],p);
}
else up(1,1,n,1,l[u]-1,p) , up(1,1,n,r[v]+1,n,p) , up(1,1,n,r[u]+1,l[v]-1,p);
printf("%d\n",n-tr[1]);
}
}
注意:就算那个节点lz[o]的值为0,它还需要tr[o] = tr[ls] + tr[rs];